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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to