From: Sascha Wildner Date: Wed, 5 Dec 2012 22:28:33 +0000 (+0100) Subject: twe(4): Sync with FreeBSD. X-Git-Tag: v3.4.0rc~728 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/f21d89e98567281344ac5c690a8c2439fcf14abf twe(4): Sync with FreeBSD. Main change is making it MPSAFE. There's also some cleanup and misc fixes. I tested it with an Escalade 8506-8. --- diff --git a/share/man/man4/twe.4 b/share/man/man4/twe.4 index e37163ea19..1495fa18a1 100644 --- a/share/man/man4/twe.4 +++ b/share/man/man4/twe.4 @@ -22,7 +22,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: src/share/man/man4/twe.4,v 1.17 2006/05/20 09:39:28 brueffer Exp $ +.\" $FreeBSD: src/share/man/man4/twe.4,v 1.18 2012/11/17 01:50:48 svnexp Exp $ .\" .Dd December 31, 2010 .Dt TWE 4 diff --git a/sys/dev/raid/twe/Makefile b/sys/dev/raid/twe/Makefile index 0c3041a8e3..73bec5087d 100644 --- a/sys/dev/raid/twe/Makefile +++ b/sys/dev/raid/twe/Makefile @@ -1,4 +1,4 @@ -# $FreeBSD: src/sys/modules/twe/Makefile,v 1.7 2005/08/10 04:01:21 obrien Exp $ +# $FreeBSD: src/sys/modules/twe/Makefile,v 1.8 2012/11/17 01:53:01 svnexp Exp $ KMOD= twe SRCS= bus_if.h device_if.h pci_if.h twe.c twe_freebsd.c diff --git a/sys/dev/raid/twe/twe.c b/sys/dev/raid/twe/twe.c index 96836843f5..4add740bbb 100644 --- a/sys/dev/raid/twe/twe.c +++ b/sys/dev/raid/twe/twe.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twe/twe.c,v 1.30 2009/12/25 17:34:43 mav Exp $ + * $FreeBSD: src/sys/dev/twe/twe.c,v 1.34 2012/11/17 01:52:19 svnexp Exp $ */ /* @@ -68,7 +68,7 @@ static int twe_del_unit(struct twe_softc *sc, int unit); /* * 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 unit) 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 unit) 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 unit) 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; @@ -257,6 +270,7 @@ twe_add_unit(struct twe_softc *sc, int unit) } 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); @@ -273,6 +287,7 @@ twe_del_unit(struct twe_softc *sc, int unit) { int error; + TWE_CONFIG_ASSERT_LOCKED(sc); if (unit < 0 || unit >= TWE_MAX_UNITS) return (ENXIO); @@ -294,12 +309,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 @@ -318,6 +336,7 @@ twe_init(struct twe_softc *sc) * Finally enable interrupts. */ twe_enable_interrupts(sc); + TWE_IO_UNLOCK(sc); } /******************************************************************************** @@ -329,6 +348,7 @@ twe_deinit(struct twe_softc *sc) /* * Mark the controller as shutting down, and disable any further interrupts. */ + twe_lockassert(&sc->twe_io_lock); sc->twe_state |= TWE_STATE_SHUTDOWN; twe_disable_interrupts(sc); @@ -367,7 +387,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); } /******************************************************************************** @@ -379,12 +399,13 @@ twe_startio(struct twe_softc *sc) { struct twe_request *tr; TWE_Command *cmd; - twe_bio *bio; + struct bio *bio; struct buf *bp; int error; debug_called(4); + twe_lockassert(&sc->twe_io_lock); if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN)) return; @@ -442,7 +463,7 @@ twe_startio(struct twe_softc *sc) break; tr->tr_status = TWE_CMD_ERROR; if (tr->tr_private != NULL) { - bio = (twe_bio *)tr->tr_private; + bio = (struct bio *)(tr->tr_private); bp = bio->bio_buf; bp->b_error = error; bp->b_flags |= B_ERROR; @@ -507,14 +528,31 @@ twe_ioctl(struct twe_softc *sc, u_long ioctlcmd, void *addr) struct twe_request *tr; u_int8_t srid; 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 = kmalloc(tr_length, M_DEVBUF, M_WAITOK); + error = copyin(tu->tu_data, data, tu->tu_size); + if (error) { + kfree(data, M_DEVBUF); + break; + } + } else + data = NULL; + /* get a request */ + TWE_IO_LOCK(sc); while (twe_get_request(sc, &tr)) - tsleep(sc, 0, "twioctl", hz); + lksleep(sc, &sc->twe_io_lock, 0, "twioctl", hz); /* * Save the command's request ID, copy the user-supplied command in, @@ -529,16 +567,14 @@ twe_ioctl(struct twe_softc *sc, u_long ioctlcmd, void *addr) * 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; - if (tr->tr_length > 0) { - tr->tr_data = kmalloc(tr->tr_length, M_DEVBUF, M_WAITOK); - if ((error = copyin(tu->tu_data, tr->tr_data, tu->tu_size)) != 0) - goto cmd_done; + tr->tr_length = tr_length; + tr->tr_data = data; + if (tr->tr_length > 0) 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; @@ -553,8 +589,9 @@ twe_ioctl(struct twe_softc *sc, u_long ioctlcmd, void *addr) /* free resources */ if (tr->tr_data != NULL) kfree(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; @@ -567,7 +604,9 @@ twe_ioctl(struct twe_softc *sc, u_long ioctlcmd, void *addr) 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: @@ -578,22 +617,28 @@ twe_ioctl(struct twe_softc *sc, u_long ioctlcmd, void *addr) /* 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: - crit_enter(); + TWE_IO_LOCK(sc); while ((*aen_code = twe_dequeue_aen(sc)) == TWE_AEN_QUEUE_EMPTY) { - error = tsleep(&sc->twe_aen_queue, PCATCH, "tweaen", 0); + error = lksleep(&sc->twe_aen_queue, &sc->twe_io_lock, PCATCH, + "tweaen", 0); if (error == EINTR) break; } - crit_exit(); + 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; @@ -612,21 +657,30 @@ twe_ioctl(struct twe_softc *sc, u_long ioctlcmd, void *addr) case TWEIO_SET_PARAM: data = kmalloc(tp->tp_size, M_DEVBUF, M_WAITOK); error = copyin(tp->tp_data, data, tp->tp_size); - if (error == 0) + 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); + } kfree(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 +778,7 @@ twe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_siz debug_called(4); + twe_lockassert(&sc->twe_io_lock); tr = NULL; param = NULL; @@ -816,6 +871,7 @@ twe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size, debug_called(4); + twe_lockassert(&sc->twe_io_lock); tr = NULL; param = NULL; error = ENOMEM; @@ -872,6 +928,8 @@ twe_init_connection(struct twe_softc *sc, int mode) debug_called(4); + twe_lockassert(&sc->twe_io_lock); + /* get a command */ if (twe_get_request(sc, &tr)) return(0); @@ -903,14 +961,13 @@ twe_wait_request(struct twe_request *tr) { debug_called(4); + twe_lockassert(&tr->tr_sc->twe_io_lock); tr->tr_flags |= TWE_CMD_SLEEPER; tr->tr_status = TWE_CMD_BUSY; twe_enqueue_ready(tr); twe_startio(tr->tr_sc); - crit_enter(); while (tr->tr_status == TWE_CMD_BUSY) - tsleep(tr, 0, "twewait", 0); - crit_exit(); + lksleep(tr, &tr->tr_sc->twe_io_lock, 0, "twewait", 0); return(tr->tr_status != TWE_CMD_COMPLETE); } @@ -945,7 +1002,7 @@ twe_immediate_request(struct twe_request *tr, int usetmp) /* 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); @@ -961,7 +1018,7 @@ twe_completeio(struct twe_request *tr) { TWE_Command *cmd = TWE_FIND_COMMAND(tr); struct twe_softc *sc = tr->tr_sc; - struct bio *bio = (twe_bio *)tr->tr_private; + struct bio *bio = tr->tr_private; struct buf *bp = bio->bio_buf; debug_called(4); @@ -995,7 +1052,7 @@ twe_reset(struct twe_softc *sc) /* * Sleep for a short period to allow AENs to be signalled. */ - tsleep(sc, 0, "twereset", hz); + lksleep(sc, &sc->twe_io_lock, 0, "twereset", hz); /* * Disable interrupts from the controller, and mask any accidental entry @@ -1003,7 +1060,6 @@ twe_reset(struct twe_softc *sc) */ twe_printf(sc, "controller reset in progress...\n"); twe_disable_interrupts(sc); - crit_enter(); /* * Try to soft-reset the controller. @@ -1035,11 +1091,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: - crit_exit(); twe_enable_interrupts(sc); } @@ -1059,11 +1113,13 @@ twe_start(struct twe_request *tr) { struct twe_softc *sc = tr->tr_sc; TWE_Command *cmd; - int i, done; + int i; u_int32_t status_reg; debug_called(4); + twe_lockassert(&sc->twe_io_lock); + /* mark the command as currently being processed */ tr->tr_status = TWE_CMD_BUSY; cmd = TWE_FIND_COMMAND(tr); @@ -1074,8 +1130,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--) { - crit_enter(); + for (i = 100000; (i > 0); i--) { /* check to see if we can post a command */ status_reg = TWE_STATUS(sc); @@ -1085,7 +1140,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) { @@ -1096,14 +1151,11 @@ twe_start(struct twe_request *tr) debug(3, "queued request %d for polling caller", cmd->generic.request_id); } #endif - } - crit_exit(); /* drop critical section 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 @@ -1119,7 +1171,7 @@ 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; @@ -1131,7 +1183,6 @@ twe_done(struct twe_softc *sc) /* loop collecting completed commands */ found = 0; - crit_enter(); for (;;) { status_reg = TWE_STATUS(sc); twe_check_bits(sc, status_reg); /* XXX should this fail? */ @@ -1154,10 +1205,9 @@ twe_done(struct twe_softc *sc) break; /* no response ready */ } } - crit_exit(); /* if we've completed any commands, try posting some more */ - if (found) + if (found && startio) twe_startio(sc); /* handle completion and timeouts */ @@ -1258,6 +1308,7 @@ twe_soft_reset(struct twe_softc *sc) debug_called(2); + twe_lockassert(&sc->twe_io_lock); TWE_SOFT_RESET(sc); if (twe_wait_status(sc, TWE_STATUS_ATTENTION_INTERRUPT, 30)) { @@ -1395,6 +1446,7 @@ twe_drain_aen_queue(struct twe_softc *sc) { u_int16_t aen; + twe_lockassert(&sc->twe_io_lock); for (;;) { if (twe_get_param_2(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, &aen)) return(1); @@ -1420,10 +1472,10 @@ twe_enqueue_aen(struct twe_softc *sc, u_int16_t aen) debug_called(4); + twe_lockassert(&sc->twe_io_lock); if ((msg = twe_format_aen(sc, aen)) != NULL) twe_printf(sc, "AEN: <%s>\n", msg); - crit_enter(); /* enqueue the AEN */ next = ((sc->twe_aen_head + 1) % TWE_Q_LENGTH); nextnext = ((sc->twe_aen_head + 2) % TWE_Q_LENGTH); @@ -1446,7 +1498,6 @@ twe_enqueue_aen(struct twe_softc *sc, u_int16_t aen) sc->twe_wait_aen = -1; wakeup(&sc->twe_wait_aen); } - crit_exit(); } /******************************************************************************** @@ -1461,6 +1512,7 @@ twe_dequeue_aen(struct twe_softc *sc) debug_called(4); + twe_lockassert(&sc->twe_io_lock); if (sc->twe_aen_tail == sc->twe_aen_head) { result = TWE_AEN_QUEUE_EMPTY; } else { @@ -1481,12 +1533,10 @@ twe_find_aen(struct twe_softc *sc, u_int16_t aen) int i, missing; missing = 1; - crit_enter(); 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; } - crit_exit(); return(missing); } @@ -1510,15 +1560,13 @@ twe_wait_aen(struct twe_softc *sc, int aen, int timeout) expiry = time_second + timeout; found = 0; - crit_enter(); sc->twe_wait_aen = aen; do { twe_fetch_aen(sc); - tsleep(&sc->twe_wait_aen, PZERO, "twewaen", hz); + lksleep(&sc->twe_wait_aen, &sc->twe_io_lock, 0, "twewaen", hz); if (sc->twe_wait_aen == -1) found = 1; } while ((time_second <= expiry) && !found); - crit_exit(); return(!found); } #endif @@ -1540,6 +1588,8 @@ twe_get_request(struct twe_softc *sc, struct twe_request **tr) TWE_Command *cmd; debug_called(4); + twe_lockassert(&sc->twe_io_lock); + /* try to reuse an old buffer */ *tr = twe_dequeue_free(sc); @@ -1566,6 +1616,7 @@ twe_release_request(struct twe_request *tr) { debug_called(4); + twe_lockassert(&tr->tr_sc->twe_io_lock); if (tr->tr_private != NULL) twe_panic(tr->tr_sc, "tr_private != NULL"); twe_enqueue_free(tr); @@ -1590,6 +1641,8 @@ twe_describe_controller(struct twe_softc *sc) debug_called(2); + TWE_IO_LOCK(sc); + /* get the port count */ twe_get_param_1(sc, TWE_PARAM_CONTROLLER, TWE_PARAM_CONTROLLER_PortCount, &ports); @@ -1640,6 +1693,7 @@ twe_describe_controller(struct twe_softc *sc) if (p[0]) kfree(p[0], M_DEVBUF); } + TWE_IO_UNLOCK(sc); } /******************************************************************************** @@ -1721,7 +1775,6 @@ twe_check_bits(struct twe_softc *sc, u_int32_t status_reg) static char * twe_format_aen(struct twe_softc *sc, u_int16_t aen) { - static char buf[80]; device_t child; char *code, *msg; @@ -1738,25 +1791,28 @@ twe_format_aen(struct twe_softc *sc, u_int16_t aen) case 'c': if ((child = sc->twe_drive[TWE_AEN_UNIT(aen)].td_disk) != NULL) { - ksprintf(buf, "twed%d: %s", device_get_unit(child), msg); + ksnprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf), "twed%d: %s", + device_get_unit(child), msg); } else { - ksprintf(buf, "twe%d: %s for unknown unit %d", device_get_unit(sc->twe_dev), - msg, TWE_AEN_UNIT(aen)); + ksnprintf(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': - ksprintf(buf, "twe%d: port %d: %s", device_get_unit(sc->twe_dev), TWE_AEN_UNIT(aen), - msg); - return(buf); + ksnprintf(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; } - ksprintf(buf, "unknown AEN 0x%x", aen); - return(buf); + ksnprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf), "unknown AEN 0x%x", aen); + return(sc->twe_aen_buf); } /******************************************************************************** diff --git a/sys/dev/raid/twe/twe_compat.h b/sys/dev/raid/twe/twe_compat.h index 6ed0a20417..16f931c965 100644 --- a/sys/dev/raid/twe/twe_compat.h +++ b/sys/dev/raid/twe/twe_compat.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twe/twe_compat.h,v 1.14 2005/05/29 04:42:26 nyan Exp $ + * $FreeBSD: src/sys/dev/twe/twe_compat.h,v 1.17 2012/11/17 01:52:19 svnexp Exp $ */ /* * Portability and compatibility interfaces. @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include #include #include @@ -56,10 +56,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) 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) bus_read_4((sc)->twe_io, 0xc) /* * FreeBSD-specific softc elements @@ -70,8 +70,6 @@ device_t twe_dev; /* bus device */ \ cdev_t 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 */ \ @@ -83,7 +81,9 @@ void *twe_immediate; /* immediate commands */ \ bus_dmamap_t twe_immediate_map; \ struct sysctl_ctx_list sysctl_ctx; \ - struct sysctl_oid *sysctl_tree; + struct sysctl_oid *sysctl_tree; \ + struct lock twe_io_lock; \ + struct lock twe_config_lock; /* * FreeBSD-specific request elements @@ -98,5 +98,21 @@ #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) -typedef struct bio twe_bio; -typedef struct bio_queue_head twe_bioq; +#define TWE_IO_LOCK(sc) lockmgr(&(sc)->twe_io_lock, LK_EXCLUSIVE) +#define TWE_IO_UNLOCK(sc) lockmgr(&(sc)->twe_io_lock, LK_RELEASE) +#define TWE_CONFIG_LOCK(sc) lockmgr(&(sc)->twe_config_lock, LK_EXCLUSIVE) +#define TWE_CONFIG_UNLOCK(sc) lockmgr(&(sc)->twe_config_lock, LK_RELEASE) +#define TWE_CONFIG_ASSERT_LOCKED(sc) KKASSERT(lockowned(&(sc)->twe_config_lock)) + +/* + * XXX + * + * Mimics FreeBSD's mtx_assert() behavior. + * We might want a global lockassert() function in the future. + */ +static __inline void +twe_lockassert(struct lock *lockp) +{ + if (panicstr == NULL && !dumping) + KKASSERT(lockstatus(lockp, curthread) != 0); +} diff --git a/sys/dev/raid/twe/twe_freebsd.c b/sys/dev/raid/twe/twe_freebsd.c index bea43f470c..acf4bde8ef 100644 --- a/sys/dev/raid/twe/twe_freebsd.c +++ b/sys/dev/raid/twe/twe_freebsd.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twe/twe_freebsd.c,v 1.48 2009/12/25 17:34:43 mav Exp $ + * $FreeBSD: src/sys/dev/twe/twe_freebsd.c,v 1.54 2012/11/17 01:52:19 svnexp Exp $ */ /* @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -68,7 +69,7 @@ static d_close_t twe_close; static d_ioctl_t twe_ioctl_wrapper; static struct dev_ops twe_ops = { - { "twe", 0, 0 }, + { "twe", 0, D_MPSAFE }, .d_open = twe_open, .d_close = twe_close, .d_ioctl = twe_ioctl_wrapper, @@ -83,7 +84,13 @@ twe_open(struct dev_open_args *ap) cdev_t dev = ap->a_head.a_dev; 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 +103,9 @@ twe_close(struct dev_close_args *ap) cdev_t dev = ap->a_head.a_dev; 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); } @@ -139,8 +148,6 @@ static device_method_t twe_methods[] = { DEVMETHOD(device_suspend, twe_suspend), DEVMETHOD(device_resume, twe_resume), - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), { 0, 0 } }; @@ -178,7 +185,6 @@ twe_attach(device_t dev) { struct twe_softc *sc; int rid, error; - u_int32_t command; debug_called(4); @@ -187,6 +193,8 @@ twe_attach(device_t dev) */ sc = device_get_softc(dev); sc->twe_dev = dev; + lockinit(&sc->twe_io_lock, "twe I/O", 0, LK_CANRECURSE); + lockinit(&sc->twe_config_lock, "twe config", 0, LK_CANRECURSE); sysctl_ctx_init(&sc->sysctl_ctx); sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, @@ -200,19 +208,10 @@ twe_attach(device_t dev) 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. @@ -224,8 +223,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. @@ -254,7 +251,7 @@ twe_attach(device_t dev) twe_free(sc); return(ENXIO); } - if (bus_setup_intr(sc->twe_dev, sc->twe_irq, 0, + if (bus_setup_intr(sc->twe_dev, sc->twe_irq, INTR_MPSAFE, twe_pci_intr, sc, &sc->twe_intr, NULL)) { twe_printf(sc, "can't set up interrupt\n"); twe_free(sc); @@ -427,6 +424,8 @@ twe_free(struct twe_softc *sc) dev_ops_remove_minor(&twe_ops, device_get_unit(sc->twe_dev)); sysctl_ctx_free(&sc->sysctl_ctx); + lockuninit(&sc->twe_config_lock); + lockuninit(&sc->twe_io_lock); } /******************************************************************************** @@ -436,27 +435,30 @@ static int twe_detach(device_t dev) { struct twe_softc *sc = device_get_softc(dev); - int error; debug_called(4); - error = EBUSY; - crit_enter(); - 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); + sc->twe_state &= ~TWE_STATE_DETACHING; + TWE_IO_UNLOCK(sc); + return (EBUSY); + } twe_free(sc); - error = 0; - out: - crit_exit(); - return(error); + return(0); } /******************************************************************************** @@ -473,26 +475,28 @@ twe_shutdown(device_t dev) debug_called(4); - crit_enter(); - /* * Delete all our child devices. */ + TWE_CONFIG_LOCK(sc); for (i = 0; i < TWE_MAX_UNITS; i++) { if (sc->twe_drive[i].td_disk != 0) { - if ((error = twe_detach_drive(sc, i)) != 0) - goto out; + if ((error = twe_detach_drive(sc, i)) != 0) { + TWE_CONFIG_UNLOCK(sc); + return (error); + } } } + TWE_CONFIG_UNLOCK(sc); /* * Bring the controller down. */ + TWE_IO_LOCK(sc); twe_deinit(sc); + TWE_IO_UNLOCK(sc); -out: - crit_exit(); - return(error); + return(0); } /******************************************************************************** @@ -505,8 +509,9 @@ twe_suspend(device_t dev) debug_called(4); - crit_enter(); + TWE_IO_LOCK(sc); sc->twe_state |= TWE_STATE_SUSPEND; + TWE_IO_UNLOCK(sc); twe_disable_interrupts(sc); crit_exit(); @@ -524,8 +529,10 @@ twe_resume(device_t dev) debug_called(4); + TWE_IO_LOCK(sc); sc->twe_state &= ~TWE_STATE_SUSPEND; twe_enable_interrupts(sc); + TWE_IO_UNLOCK(sc); return(0); } @@ -537,7 +544,11 @@ twe_resume(device_t dev) static void twe_pci_intr(void *arg) { - twe_intr((struct twe_softc *)arg); + struct twe_softc *sc = arg; + + TWE_IO_LOCK(sc); + twe_intr(sc); + TWE_IO_UNLOCK(sc); } /******************************************************************************** @@ -566,8 +577,10 @@ twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr) char buf[80]; int error; + get_mplock(); dr->td_disk = device_add_child(sc->twe_dev, NULL, -1); if (dr->td_disk == NULL) { + rel_mplock(); twe_printf(sc, "Cannot add unit\n"); return (EIO); } @@ -583,7 +596,9 @@ twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr) twe_describe_code(twe_table_unitstate, dr->td_state & TWE_PARAM_UNITSTATUS_MASK)); device_set_desc_copy(dr->td_disk, buf); - if ((error = bus_generic_attach(sc->twe_dev)) != 0) { + error = device_probe_and_attach(dr->td_disk); + rel_mplock(); + if (error != 0) { twe_printf(sc, "Cannot attach unit to controller. error = %d\n", error); return (EIO); } @@ -600,7 +615,11 @@ twe_detach_drive(struct twe_softc *sc, int unit) { int error = 0; - if ((error = device_delete_child(sc->twe_dev, sc->twe_drive[unit].td_disk)) != 0) { + TWE_CONFIG_ASSERT_LOCKED(sc); + get_mplock(); + error = device_delete_child(sc->twe_dev, sc->twe_drive[unit].td_disk); + rel_mplock(); + if (error != 0) { twe_printf(sc, "failed to delete unit %d\n", unit); return(error); } @@ -666,7 +685,7 @@ static d_strategy_t twed_strategy; static d_dump_t twed_dump; static struct dev_ops twed_ops = { - { "twed", 0, D_DISK }, + { "twed", 0, D_DISK | D_MPSAFE}, .d_open = twed_open, .d_close = twed_close, .d_read = physread, @@ -749,10 +768,12 @@ twed_strategy(struct dev_strategy_args *ap) devstat_start_transaction(&sc->twed_stats); /* queue the bio on the controller */ + TWE_IO_LOCK(sc->twed_controller); twe_enqueue_bio(sc->twed_controller, bio); /* poke the controller to start I/O */ twe_startio(sc->twed_controller); + TWE_IO_UNLOCK(sc->twed_controller); return(0); } @@ -794,7 +815,7 @@ twed_intr(struct bio *bio) debug_called(4); /* if no error, transfer completed */ - if ((bp->b_flags & B_ERROR) == 0) + if (!(bp->b_flags & B_ERROR)) bp->b_resid = 0; devstat_end_transaction_buf(&sc->twed_stats, bp); biodone(bio); @@ -899,13 +920,13 @@ twed_detach(device_t dev) /******************************************************************************** * Allocate a command buffer */ -MALLOC_DEFINE(TWE_MALLOC_CLASS, "twe_commands", "twe commands"); +static MALLOC_DEFINE(TWE_MALLOC_CLASS, "twe_commands", "twe commands"); struct twe_request * twe_allocate_request(struct twe_softc *sc, int tag) { struct twe_request *tr; - int aligned_size; + int aligned_size; /* * TWE requires requests to be 512-byte aligned. Depend on malloc() @@ -914,8 +935,8 @@ twe_allocate_request(struct twe_softc *sc, int tag) * allocator only guarentees same-size alignment for power-of-2 requests. */ aligned_size = (sizeof(struct twe_request) + TWE_ALIGNMASK) & - ~TWE_ALIGNMASK; - tr = kmalloc(aligned_size, TWE_MALLOC_CLASS, M_INTWAIT|M_ZERO); + ~TWE_ALIGNMASK; + tr = kmalloc(aligned_size, TWE_MALLOC_CLASS, M_INTWAIT | M_ZERO); tr->tr_sc = sc; tr->tr_tag = tag; if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_dmamap)) { @@ -1077,6 +1098,7 @@ twe_map_request(struct twe_request *tr) debug_called(4); + twe_lockassert(&sc->twe_io_lock); if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN)) { twe_requeue_ready(tr); return (EBUSY); @@ -1196,10 +1218,8 @@ twe_report(void) struct twe_softc *sc; int i; - crit_enter(); for (i = 0; (sc = devclass_get_softc(twe_devclass, i)) != NULL; i++) twe_print_controller(sc); kprintf("twed: total bio count in %u out %u\n", twed_bio_in, twed_bio_out); - crit_exit(); } #endif diff --git a/sys/dev/raid/twe/twe_tables.h b/sys/dev/raid/twe/twe_tables.h index c8871a2802..40ef35e861 100644 --- a/sys/dev/raid/twe/twe_tables.h +++ b/sys/dev/raid/twe/twe_tables.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twe/twe_tables.h,v 1.4 2003/12/02 07:57:20 ps Exp $ + * $FreeBSD: src/sys/dev/twe/twe_tables.h,v 1.5 2012/11/17 01:52:19 svnexp Exp $ */ /* diff --git a/sys/dev/raid/twe/tweio.h b/sys/dev/raid/twe/tweio.h index aa69c72ce8..7e75b020f3 100644 --- a/sys/dev/raid/twe/tweio.h +++ b/sys/dev/raid/twe/tweio.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twe/tweio.h,v 1.5 2005/02/17 19:05:42 vkashyap Exp $ + * $FreeBSD: src/sys/dev/twe/tweio.h,v 1.6 2012/11/17 01:52:19 svnexp Exp $ */ #include diff --git a/sys/dev/raid/twe/twereg.h b/sys/dev/raid/twe/twereg.h index 93ca338ff7..58828f6a9c 100644 --- a/sys/dev/raid/twe/twereg.h +++ b/sys/dev/raid/twe/twereg.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twe/twereg.h,v 1.11 2004/05/12 04:10:37 vkashyap Exp $ + * $FreeBSD: src/sys/dev/twe/twereg.h,v 1.12 2012/11/17 01:52:19 svnexp Exp $ */ /* diff --git a/sys/dev/raid/twe/twevar.h b/sys/dev/raid/twe/twevar.h index 25ab13324d..6f77dac29c 100644 --- a/sys/dev/raid/twe/twevar.h +++ b/sys/dev/raid/twe/twevar.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twe/twevar.h,v 1.15 2009/12/25 17:34:43 mav Exp $ + * $FreeBSD: src/sys/dev/twe/twevar.h,v 1.19 2012/11/17 01:52:19 svnexp Exp $ */ #define TWE_DRIVER_VERSION_STRING "1.50.01.002" @@ -128,7 +128,7 @@ struct twe_softc { /* controller queues and arrays */ TAILQ_HEAD(, twe_request) twe_free; /* command structures available for reuse */ - twe_bioq twe_bioq; /* outstanding I/O operations */ + struct bio_queue_head twe_bioq; /* outstanding I/O operations */ TAILQ_HEAD(, twe_request) twe_ready; /* requests ready for the controller */ TAILQ_HEAD(, twe_request) twe_busy; /* requests busy in the controller */ TAILQ_HEAD(, twe_request) twe_complete; /* active commands (busy or waiting for completion) */ @@ -139,6 +139,7 @@ struct twe_softc u_int16_t twe_aen_queue[TWE_Q_LENGTH]; /* AENs queued for userland tool(s) */ int twe_aen_head, twe_aen_tail; /* ringbuffer pointers for AEN queue */ int twe_wait_aen; /* wait-for-aen notification */ + char twe_aen_buf[80]; /* AEN format buffer */ /* controller status */ int twe_state; @@ -148,6 +149,7 @@ struct twe_softc #define TWE_STATE_SUSPEND (1<<3) /* controller is suspended */ #define TWE_STATE_FRZN (1<<4) /* got EINPROGRESS */ #define TWE_STATE_CTLR_BUSY (1<<5) /* controller cmd queue full */ +#define TWE_STATE_DETACHING (1<<6) /* controller is being shut down */ int twe_host_id; struct twe_qstat twe_qstat[TWEQ_COUNT]; /* queue statistics */ @@ -178,7 +180,7 @@ extern int twe_detach_drive(struct twe_softc *sc, int unit); /* detach drive */ extern void twe_clear_pci_parity_error(struct twe_softc *sc); extern void twe_clear_pci_abort(struct twe_softc *sc); -extern void twed_intr(twe_bio *bp); /* return bio from core */ +extern void twed_intr(struct bio *bp); /* return bio from core */ extern struct twe_request *twe_allocate_request(struct twe_softc *sc, int tag); /* allocate request structure */ extern void twe_free_request(struct twe_request *tr); /* free request structure */ extern int twe_map_request(struct twe_request *tr); /* make request visible to controller, do s/g */ @@ -223,39 +225,31 @@ twe_initq_ ## name (struct twe_softc *sc) \ static __inline void \ twe_enqueue_ ## name (struct twe_request *tr) \ { \ - crit_enter(); \ TAILQ_INSERT_TAIL(&tr->tr_sc->twe_ ## name, tr, tr_link); \ TWEQ_ADD(tr->tr_sc, index); \ - crit_exit(); \ } \ static __inline void \ twe_requeue_ ## name (struct twe_request *tr) \ { \ - crit_enter(); \ TAILQ_INSERT_HEAD(&tr->tr_sc->twe_ ## name, tr, tr_link); \ TWEQ_ADD(tr->tr_sc, index); \ - crit_exit(); \ } \ static __inline struct twe_request * \ twe_dequeue_ ## name (struct twe_softc *sc) \ { \ struct twe_request *tr; \ \ - crit_enter(); \ if ((tr = TAILQ_FIRST(&sc->twe_ ## name)) != NULL) { \ TAILQ_REMOVE(&sc->twe_ ## name, tr, tr_link); \ TWEQ_REMOVE(sc, index); \ } \ - crit_exit(); \ return(tr); \ } \ static __inline void \ twe_remove_ ## name (struct twe_request *tr) \ { \ - crit_enter(); \ TAILQ_REMOVE(&tr->tr_sc->twe_ ## name, tr, tr_link); \ TWEQ_REMOVE(tr->tr_sc, index); \ - crit_exit(); \ } TWEQ_REQUEST_QUEUE(free, TWEQ_FREE) @@ -276,11 +270,9 @@ twe_initq_bio(struct twe_softc *sc) static __inline void twe_enqueue_bio(struct twe_softc *sc, struct bio *bio) { - crit_enter(); bioqdisksort(&sc->twe_bioq, bio); /* bioq_insert_tail(&sc->twe_bioq, bio); */ TWEQ_ADD(sc, TWEQ_BIO); - crit_exit(); } static __inline @@ -289,11 +281,9 @@ twe_dequeue_bio(struct twe_softc *sc) { struct bio *bio; - crit_enter(); if ((bio = bioq_first(&sc->twe_bioq)) != NULL) { bioq_remove(&sc->twe_bioq, bio); TWEQ_REMOVE(sc, TWEQ_BIO); } - crit_exit(); return(bio); }