Update the TWE 3ware/AMCC driver code, bringing in all the fixes made
authorHiten Pandya <hmp@dragonflybsd.org>
Mon, 22 Aug 2005 21:16:20 +0000 (21:16 +0000)
committerHiten Pandya <hmp@dragonflybsd.org>
Mon, 22 Aug 2005 21:16:20 +0000 (21:16 +0000)
by Vinod Kashyap and Paul Saab in FreeBSD-5/STABLE, and retaining
those by David Rhodus and Matthew Dillon.

Remove some compatibility preprocessor BUF/BIO compatibility macros.

Changeset thoroughly tested by Tomaz Borstnar, Matthew Dillon and
David Rhodus.  Inspired by a heads-up from YONETANI Tomokazu.

sys/dev/raid/twe/twe.c
sys/dev/raid/twe/twe_compat.h
sys/dev/raid/twe/twe_freebsd.c
sys/dev/raid/twe/twe_tables.h
sys/dev/raid/twe/tweio.h
sys/dev/raid/twe/twereg.h
sys/dev/raid/twe/twevar.h

index da4a964..fd01ede 100644 (file)
@@ -1,5 +1,7 @@
 /*-
  * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2003 Paul Saab
+ * Copyright (c) 2003 Vinod Kashyap
  * Copyright (c) 2000 BSDi
  * All rights reserved.
  *
  * 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.1.2.6 2002/03/07 09:57:02 msmith Exp $
- *     $DragonFly: src/sys/dev/raid/twe/twe.c,v 1.11 2005/06/26 22:03:29 dillon Exp $
+ *     $FreeBSD: src/sys/dev/twe/twe.c,v 1.1.2.10 2004/06/11 18:57:31 vkashyap Exp $
+ *     $DragonFly: src/sys/dev/raid/twe/twe.c,v 1.12 2005/08/22 21:16:20 hmp Exp $
  */
 
 /*
  * Driver for the 3ware Escalade family of IDE RAID controllers.
  */
 
-#include "twe_compat.h"
-#include "twereg.h"
-#include "tweio.h"
-#include "twevar.h"
+#include <dev/raid/twe/twe_compat.h>
+#include <dev/raid/twe/twereg.h>
 #define TWE_DEFINE_TABLES
-#include "twe_tables.h"
+#include <dev/raid/twe/twe_tables.h>
+#include <dev/raid/twe/tweio.h>
+#include <dev/raid/twe/twevar.h>
 
 /*
  * Command submission.
@@ -61,13 +63,12 @@ static int  twe_wait_request(struct twe_request *tr);
 static int     twe_immediate_request(struct twe_request *tr);
 static void    twe_completeio(struct twe_request *tr);
 static void    twe_reset(struct twe_softc *sc);
-static void    twe_add_unit(struct twe_softc *sc, int unit);
-static void    twe_del_unit(struct twe_softc *sc, int unit);
+static int     twe_add_unit(struct twe_softc *sc, int unit);
+static int     twe_del_unit(struct twe_softc *sc, int unit);
 
 /*
  * Command I/O to controller.
  */
-static int     twe_start(struct twe_request *tr);
 static void    twe_done(struct twe_softc *sc);
 static void    twe_complete(struct twe_softc *sc);
 static int     twe_wait_status(struct twe_softc *sc, u_int32_t status, int timeout);
@@ -88,7 +89,7 @@ static void   twe_command_intr(struct twe_softc *sc);
 static int     twe_fetch_aen(struct twe_softc *sc);
 static void    twe_handle_aen(struct twe_request *tr);
 static void    twe_enqueue_aen(struct twe_softc *sc, u_int16_t aen);
-static int     twe_dequeue_aen(struct twe_softc *sc);
+static u_int16_t       twe_dequeue_aen(struct twe_softc *sc);
 static int     twe_drain_aen_queue(struct twe_softc *sc);
 static int     twe_find_aen(struct twe_softc *sc, u_int16_t aen);
 
@@ -192,7 +193,7 @@ twe_setup(struct twe_softc *sc)
     return(0);
 }
 
-static void
+static int
 twe_add_unit(struct twe_softc *sc, int unit)
 {
     struct twe_drive           *dr;
@@ -200,40 +201,46 @@ twe_add_unit(struct twe_softc *sc, int unit)
     u_int16_t                  dsize;
     TWE_Param                  *drives = NULL, *param = NULL;
     TWE_Unit_Descriptor                *ud;
+    int                                error = 0;
 
     if (unit < 0 || unit > TWE_MAX_UNITS)
-       return;
-
+       return (EINVAL);
     /*
      * The controller is in a safe state, so try to find drives attached to it.
      */
     if ((drives = twe_get_param(sc, TWE_PARAM_UNITSUMMARY, TWE_PARAM_UNITSUMMARY_Status,
                                TWE_MAX_UNITS, NULL)) == NULL) {
        twe_printf(sc, "can't detect attached units\n");
-       return;
+       return (EIO);
     }
 
     dr = &sc->twe_drive[unit];
     /* check that the drive is online */
-    if (!(drives->data[unit] & TWE_PARAM_UNITSTATUS_Online))
+    if (!(drives->data[unit] & TWE_PARAM_UNITSTATUS_Online)) {
+       error = ENXIO;
        goto out;
+    }
 
     table = TWE_PARAM_UNITINFO + unit;
 
     if (twe_get_param_4(sc, table, TWE_PARAM_UNITINFO_Capacity, &dr->td_size)) {
        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_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_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_printf(sc, "error fetching descriptor for unit %d\n", unit);
+       error = EIO;
        goto out;
     }
     ud = (TWE_Unit_Descriptor *)param->data;
@@ -248,25 +255,31 @@ twe_add_unit(struct twe_softc *sc, int unit)
        dr->td_sectors = 32;
     }
     dr->td_cylinders = dr->td_size / (dr->td_heads * dr->td_sectors);
-    dr->td_unit = unit;
+    dr->td_twe_unit = unit;
 
-    twe_attach_drive(sc, dr);
+    error = twe_attach_drive(sc, dr);
 
 out:
     if (param != NULL)
        free(param, M_DEVBUF);
     if (drives != NULL)
        free(drives, M_DEVBUF);
+    return (error);
 }
 
-static void
+static int
 twe_del_unit(struct twe_softc *sc, int unit)
 {
+    int                error;
 
     if (unit < 0 || unit >= TWE_MAX_UNITS)
-       return;
+        return (ENXIO);
+
+    if (sc->twe_drive[unit].td_disk == NULL)
+        return (ENXIO);
 
-    twe_detach_drive(sc, unit);
+    error = twe_detach_drive(sc, unit);
+    return (error);
 }
 
 /********************************************************************************
@@ -354,7 +367,7 @@ twe_intr(struct twe_softc *sc)
        twe_command_intr(sc);
     if (status_reg & TWE_STATUS_RESPONSE_INTERRUPT)
        twe_done(sc);
-};
+}
 
 /********************************************************************************
  * Pull as much work off the softc's work queue as possible and give it to the
@@ -370,6 +383,9 @@ twe_startio(struct twe_softc *sc)
 
     debug_called(4);
 
+    if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN))
+           return;
+
     /* spin until something prevents us from doing any work */
     for (;;) {
 
@@ -408,25 +424,27 @@ twe_startio(struct twe_softc *sc)
            cmd->io.unit = TWE_BIO_UNIT(bp);
            cmd->io.block_count = (tr->tr_length + TWE_BLOCK_SIZE - 1) / TWE_BLOCK_SIZE;
            cmd->io.lba = TWE_BIO_LBA(bp);
-
-           /* map the command so the controller can work with it */
-           twe_map_request(tr);
        }
        
        /* did we find something to do? */
        if (tr == NULL)
            break;
        
-       /* try to give command to controller */
-       error = twe_start(tr);
+       /* try to map and submit the command to controller */
+       error = twe_map_request(tr);
 
        if (error != 0) {
-           if (error == EBUSY) {
-               twe_requeue_ready(tr);          /* try it again later */
-               break;                          /* don't try anything more for now */
-           }
-           /* we don't support any other return from twe_start */
-           twe_panic(sc, "twe_start returned nonsense");
+           if (error == EBUSY)
+               break;
+           tr->tr_status = TWE_CMD_ERROR;
+           if (tr->tr_private != NULL) {
+               bp = (twe_bio *)(tr->tr_private);
+               TWE_BIO_SET_ERROR(bp, error);
+               tr->tr_private = NULL;
+               twed_intr(bp);
+               twe_release_request(tr);
+           } else if (tr->tr_flags & TWE_CMD_SLEEPER)
+               wakeup_one(tr); /* wakeup the sleeping owner */
        }
     }
 }
@@ -456,7 +474,6 @@ twe_dump_blocks(struct twe_softc *sc, int unit,     u_int32_t lba, void *data, int n
     cmd->io.block_count = nblks;
     cmd->io.lba = lba;
 
-    twe_map_request(tr);
     error = twe_immediate_request(tr);
     if (error == 0)
        if (twe_report_request(tr))
@@ -477,7 +494,7 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
     union twe_statrequest      *ts = (union twe_statrequest *)addr;
     TWE_Param                  *param;
     void                       *data;
-    int                                *arg = (int *)addr;
+    unsigned short             *aen_code = (unsigned short *) addr;
     struct twe_request         *tr;
     u_int8_t                   srid;
     int                                error;
@@ -514,8 +531,9 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
        }
 
        /* run the command */
-       twe_map_request(tr);
-       twe_wait_request(tr);
+       error = twe_wait_request(tr);
+       if (error)
+           goto cmd_done;
 
        /* copy the command out again */
        bcopy(&tr->tr_command, &tu->tu_command, sizeof(TWE_Command));
@@ -553,14 +571,14 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
 
        /* poll for an AEN */
     case TWEIO_AEN_POLL:
-       *arg = twe_dequeue_aen(sc);
+       *aen_code = twe_dequeue_aen(sc);
        break;
 
        /* wait for another AEN to show up */
     case TWEIO_AEN_WAIT:
        crit_enter();
-       while ((*arg = twe_dequeue_aen(sc)) == TWE_AEN_QUEUE_EMPTY) {
-           error = tsleep(&sc->twe_aen_queue, 0 | PCATCH, "tweaen", 0);
+       while ((*aen_code = twe_dequeue_aen(sc)) == TWE_AEN_QUEUE_EMPTY) {
+           error = tsleep(&sc->twe_aen_queue, PCATCH, "tweaen", 0);
            if (error == EINTR)
                break;
        }
@@ -600,11 +618,11 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
        break;
 
     case TWEIO_ADD_UNIT:
-       twe_add_unit(sc, td->td_unit);
+       error = twe_add_unit(sc, td->td_unit);
        break;
 
     case TWEIO_DEL_UNIT:
-       twe_del_unit(sc, td->td_unit);
+       error = twe_del_unit(sc, td->td_unit);
        break;
 
        /* XXX implement ATA PASSTHROUGH */
@@ -710,7 +728,7 @@ twe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_siz
        goto err;
 
     /* get a buffer */
-    param = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_INTWAIT);
+    param = (TWE_Param *)malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_INTWAIT);
     tr->tr_data = param;
     tr->tr_length = TWE_SECTOR_SIZE;
     tr->tr_flags = TWE_CMD_DATAIN | TWE_CMD_DATAOUT;
@@ -722,9 +740,6 @@ twe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_siz
     cmd->param.unit = 0;
     cmd->param.param_count = 1;
 
-    /* map the command/data into controller-visible space */
-    twe_map_request(tr);
-
     /* fill in the outbound parameter data */
     param->table_id = table_id;
     param->parameter_id = param_id;
@@ -738,12 +753,14 @@ twe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_siz
            if (twe_report_request(tr))
                goto err;
        }
+       else
+               goto err;
        twe_release_request(tr);
        return(param);
     } else {
        tr->tr_complete = func;
-       error = twe_start(tr);
-       if (error == 0)
+       error = twe_map_request(tr);
+       if ((error == 0) || (error == EBUSY))
            return(func);
     }
 
@@ -804,7 +821,7 @@ twe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size,
        goto out;
 
     /* get a buffer */
-    param = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_INTWAIT);
+    param = (TWE_Param *)malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_INTWAIT);
     tr->tr_data = param;
     tr->tr_length = TWE_SECTOR_SIZE;
     tr->tr_flags = TWE_CMD_DATAIN | TWE_CMD_DATAOUT;
@@ -816,9 +833,6 @@ twe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size,
     cmd->param.unit = 0;
     cmd->param.param_count = 1;
 
-    /* map the command/data into controller-visible space */
-    twe_map_request(tr);
-
     /* fill in the outbound parameter data */
     param->table_id = table_id;
     param->parameter_id = param_id;
@@ -866,13 +880,8 @@ twe_init_connection(struct twe_softc *sc, int mode)
     cmd->initconnection.message_credits = mode;
     cmd->initconnection.response_queue_pointer = 0;
 
-    /* map the command into controller-visible space */
-    twe_map_request(tr);
-
     /* submit the command */
     error = twe_immediate_request(tr);
-    /* XXX check command result? */
-    twe_unmap_request(tr);
     twe_release_request(tr);
 
     if (mode == TWE_INIT_MESSAGE_CREDITS)
@@ -899,7 +908,7 @@ twe_wait_request(struct twe_request *tr)
        tsleep(tr, 0, "twewait", 0);
     crit_exit();
     
-    return(0);
+    return(tr->tr_status != TWE_CMD_COMPLETE);
 }
 
 /********************************************************************************
@@ -914,10 +923,10 @@ twe_immediate_request(struct twe_request *tr)
 
     debug_called(4);
 
-    error = 0;
-
-    if ((error = twe_start(tr)) != 0)
-       return(error);
+    tr->tr_status = TWE_CMD_BUSY;
+    if ((error = twe_map_request(tr)) != 0)
+       if (error != EBUSY)
+           return(error);
     while (tr->tr_status == TWE_CMD_BUSY){
        twe_done(tr->tr_sc);
     }
@@ -936,10 +945,9 @@ twe_completeio(struct twe_request *tr)
     debug_called(4);
 
     if (tr->tr_status == TWE_CMD_COMPLETE) {
-
-       if (twe_report_request(tr))
-           TWE_BIO_SET_ERROR(bp, EIO);
-
+       if (tr->tr_command.generic.status)
+               if (twe_report_request(tr))
+                       TWE_BIO_SET_ERROR(bp, EIO);
     } else {
        twe_panic(sc, "twe_completeio on incomplete command");
     }
@@ -1020,7 +1028,7 @@ out:
  *
  * Can be called at any interrupt level, with or without interrupts enabled.
  */
-static int
+int
 twe_start(struct twe_request *tr)
 {
     struct twe_softc   *sc = tr->tr_sc;
@@ -1060,7 +1068,7 @@ twe_start(struct twe_request *tr)
            }
 #endif
        }
-       crit_exit();    /* drop spl to allow completion interrupts */
+       crit_exit();    /* drop critical section to allow completion interrupts */
     }
 
     /* command is enqueued */
@@ -1110,6 +1118,7 @@ twe_done(struct twe_softc *sc)
            /* move to completed queue */
            twe_remove_busy(tr);
            twe_enqueue_complete(tr);
+           sc->twe_state &= ~TWE_STATE_CTLR_BUSY;
        } else {
            break;                                      /* no response ready */
        }
@@ -1298,8 +1307,8 @@ twe_command_intr(struct twe_softc *sc)
      * We don't use this, rather we try to submit commands when we receive
      * them, and when other commands have completed.  Mask it so we don't get
      * another one.
-     */
     twe_printf(sc, "command interrupt\n");
+     */
     TWE_CONTROL(sc, TWE_CONTROL_MASK_COMMAND_INTERRUPT);
 }
 
@@ -1416,10 +1425,10 @@ twe_enqueue_aen(struct twe_softc *sc, u_int16_t aen)
  *
  * We are more or less interrupt-safe, so don't block interrupts.
  */
-static int
+static u_int16_t
 twe_dequeue_aen(struct twe_softc *sc)
 {
-    int                result;
+    u_int16_t  result;
     
     debug_called(4);
 
@@ -1554,23 +1563,34 @@ twe_describe_controller(struct twe_softc *sc)
     twe_get_param_1(sc, TWE_PARAM_CONTROLLER, TWE_PARAM_CONTROLLER_PortCount, &ports);
 
     /* get version strings */
-    p[0] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_Mon,  16, NULL);
-    p[1] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_FW,   16, NULL);
-    p[2] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_BIOS, 16, NULL);
-    p[3] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCB,  8, NULL);
-    p[4] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_ATA,  8, NULL);
-    p[5] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCI,  8, NULL);
-
-    twe_printf(sc, "%d ports, Firmware %.16s, BIOS %.16s\n", ports, p[1]->data, p[2]->data);
-    if (bootverbose)
-       twe_printf(sc, "Monitor %.16s, PCB %.8s, Achip %.8s, Pchip %.8s\n", p[0]->data, p[3]->data,
-                  p[4]->data, p[5]->data);
-    free(p[0], M_DEVBUF);
-    free(p[1], M_DEVBUF);
-    free(p[2], M_DEVBUF);
-    free(p[3], M_DEVBUF);
-    free(p[4], M_DEVBUF);
-    free(p[5], M_DEVBUF);
+    p[0] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_FW,   16, NULL);
+    p[1] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_BIOS, 16, NULL);
+
+    if (p[0] && p[1])
+           twe_printf(sc, "%d ports, Firmware %.16s, BIOS %.16s\n", ports, p[0]->data, p[1]->data);
+    if (bootverbose) {
+       p[2] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_Mon,  16, NULL);
+       p[3] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCB,  8, NULL);
+       p[4] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_ATA,  8, NULL);
+       p[5] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCI,  8, NULL);
+
+       if (p[2] && p[3] && p[4] && p[5])
+               twe_printf(sc, "Monitor %.16s, PCB %.8s, Achip %.8s, Pchip %.8s\n",
+                       p[2]->data, p[3]->data, p[4]->data, p[5]->data);
+
+       if (p[2])
+               free(p[2], M_DEVBUF);
+       if (p[3])
+               free(p[3], M_DEVBUF);
+       if (p[4])
+               free(p[4], M_DEVBUF);
+       if (p[5])
+               free(p[5], M_DEVBUF);
+    }
+    if (p[0])
+       free(p[0], M_DEVBUF);
+    if (p[1])
+       free(p[1], M_DEVBUF);
 
     /* print attached drives */
     if (bootverbose) {
@@ -1587,10 +1607,27 @@ twe_describe_controller(struct twe_softc *sc)
                twe_printf(sc, "port %d, drive status unavailable\n", i);
            }
        }
-       free(p[0], M_DEVBUF);
+       if (p[0])
+           free(p[0], M_DEVBUF);
     }
 }
 
+
+/********************************************************************************
+ * Look up a text description of a numeric code and return a pointer to same.
+ */
+char *
+twe_describe_code(struct twe_code_lookup *table, u_int32_t code)
+{
+    int                i;
+
+    for (i = 0; table[i].string != NULL; i++)
+       if (table[i].code == code)
+           return(table[i].string);
+    return(table[i+1].string);
+}
+
+
 /********************************************************************************
  * Complain if the status bits aren't what we're expecting.
  *
@@ -1712,7 +1749,7 @@ twe_report_request(struct twe_request *tr)
        /*
         * The status code 0xff requests a controller reset.
         */
-       twe_printf(sc, "command returned with controller rest request\n");
+       twe_printf(sc, "command returned with controller reset request\n");
        twe_reset(sc);
        result = 1;
     } else if (cmd->generic.status > TWE_STATUS_FATAL) {
@@ -1768,12 +1805,12 @@ twe_print_controller(struct twe_softc *sc)
 
     status_reg = TWE_STATUS(sc);
     twe_printf(sc, "status   %b\n", status_reg, TWE_STATUS_BITS_DESCRIPTION);
-    twe_printf(sc, "          current  max\n");
-    twe_printf(sc, "free      %04d     %04d\n", sc->twe_qstat[TWEQ_FREE].q_length, sc->twe_qstat[TWEQ_FREE].q_max);
-    twe_printf(sc, "ready     %04d     %04d\n", sc->twe_qstat[TWEQ_READY].q_length, sc->twe_qstat[TWEQ_READY].q_max);
-    twe_printf(sc, "busy      %04d     %04d\n", sc->twe_qstat[TWEQ_BUSY].q_length, sc->twe_qstat[TWEQ_BUSY].q_max);
-    twe_printf(sc, "complete  %04d     %04d\n", sc->twe_qstat[TWEQ_COMPLETE].q_length, sc->twe_qstat[TWEQ_COMPLETE].q_max);
-    twe_printf(sc, "bioq      %04d     %04d\n", sc->twe_qstat[TWEQ_BIO].q_length, sc->twe_qstat[TWEQ_BIO].q_max);
+    twe_printf(sc, "          current  max    min\n");
+    twe_printf(sc, "free      %04d     %04d   %04d\n", sc->twe_qstat[TWEQ_FREE].q_length, sc->twe_qstat[TWEQ_FREE].q_max, sc->twe_qstat[TWEQ_FREE].q_min);
+    twe_printf(sc, "ready     %04d     %04d   %04d\n", sc->twe_qstat[TWEQ_READY].q_length, sc->twe_qstat[TWEQ_READY].q_max, sc->twe_qstat[TWEQ_READY].q_min);
+    twe_printf(sc, "busy      %04d     %04d   %04d\n", sc->twe_qstat[TWEQ_BUSY].q_length, sc->twe_qstat[TWEQ_BUSY].q_max, sc->twe_qstat[TWEQ_BUSY].q_min);
+    twe_printf(sc, "complete  %04d     %04d   %04d\n", sc->twe_qstat[TWEQ_COMPLETE].q_length, sc->twe_qstat[TWEQ_COMPLETE].q_max, sc->twe_qstat[TWEQ_COMPLETE].q_min);
+    twe_printf(sc, "bioq      %04d     %04d   %04d\n", sc->twe_qstat[TWEQ_BIO].q_length, sc->twe_qstat[TWEQ_BIO].q_max, sc->twe_qstat[TWEQ_BIO].q_min);
     twe_printf(sc, "AEN queue head %d  tail %d\n", sc->twe_aen_head, sc->twe_aen_tail);
 }      
 
index 703fb20..1c8bdd1 100644 (file)
@@ -1,5 +1,7 @@
 /*-
  * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2003 Paul Saab
+ * Copyright (c) 2003 Vinod Kashyap
  * Copyright (c) 2000 BSDi
  * All rights reserved.
  *
  * 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.1.2.3 2002/03/07 09:57:02 msmith Exp $
- * $DragonFly: src/sys/dev/raid/twe/twe_compat.h,v 1.10 2005/06/10 17:10:26 swildner Exp $
+ * $FreeBSD: src/sys/dev/twe/twe_compat.h,v 1.1.2.5 2004/04/07 22:18:00 vkashyap Exp $
+ * $DragonFly: src/sys/dev/raid/twe/twe_compat.h,v 1.11 2005/08/22 21:16:20 hmp Exp $
  */
 /*
  * Portability and compatibility interfaces.
  */
 
-#ifdef __DragonFly__
+#if defined(__FreeBSD__) || defined(__DragonFly__)
 /******************************************************************************
- * DragonFly
+ * FreeBSD-4 or DragonFly
  */
 #define TWE_SUPPORTED_PLATFORM
 
 #include <sys/param.h>
+#include <sys/cons.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/kernel.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
-
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/disk.h>
 #include <sys/stat.h>
 
+#include <sys/devicestat.h>
+
 #include <machine/bus_pio.h>
 #include <machine/bus.h>
 #include <machine/resource.h>
+#include <machine/md_var.h>
+
 #include <sys/rman.h>
 
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
 #include <bus/pci/pcireg.h>
 #include <bus/pci/pcivar.h>
 
  * All public symbols must be listed here.
  */
 #ifdef TWE_OVERRIDE
-#define twe_setup              Xtwe_setup
-#define twe_init               Xtwe_init
-#define twe_deinit             Xtwe_deinit
-#define twe_intr               Xtwe_intr
-#define twe_submit_bio         Xtwe_submit_bio
-#define twe_ioctl              Xtwe_ioctl
-#define twe_describe_controller        Xtwe_describe_controller
-#define twe_print_controller   Xtwe_print_controller
-#define twe_enable_interrupts  Xtwe_enable_interrupts
-#define twe_disable_interrupts Xtwe_disable_interrupts
-#define twe_attach_drive       Xtwe_attach_drive
-#define twed_intr              Xtwed_intr
-#define twe_allocate_request   Xtwe_allocate_request
-#define twe_free_request       Xtwe_free_request
-#define twe_map_request                Xtwe_map_request
-#define twe_unmap_request      Xtwe_unmap_request
-#define twe_describe_code      Xtwe_describe_code
-#define twe_table_status       Xtwe_table_status
-#define twe_table_unitstate    Xtwe_table_unitstate
-#define twe_table_unittype     Xtwe_table_unittype
-#define twe_table_aen          Xtwe_table_aen
-#define TWE_DRIVER_NAME                Xtwe
-#define TWED_DRIVER_NAME       Xtwed
-#define TWE_MALLOC_CLASS       M_XTWE
-#else
-#define TWE_DRIVER_NAME                twe
-#define TWED_DRIVER_NAME       twed
-#define TWE_MALLOC_CLASS       M_TWE
-#endif
+/* public symbols defined in twe.c */
+#define twe_setup                      Xtwe_setup
+#define twe_init                       Xtwe_init
+#define twe_deinit                     Xtwe_deinit
+#define twe_intr                       Xtwe_intr
+#define twe_startio                    Xtwe_startio
+#define twe_dump_blocks                        Xtwe_dump_blocks
+#define twe_ioctl                      Xtwe_ioctl
+#define twe_enable_interrupts          Xtwe_enable_interrupts
+#define twe_disable_interrupts         Xtwe_disable_interrupts
+#define twe_describe_controller                Xtwe_describe_controller
+#define twe_describe_code              Xtwe_describe_code
+#define twe_print_controller           Xtwe_print_controller
+
+/* public symbols defined in twe_freebsd.c */
+#define twe_attach_drive               Xtwe_attach_drive
+#define twe_clear_pci_parity_error     Xtwe_clear_pci_parity_error
+#define twe_clear_pci_abort            Xtwe_clear_pci_abort
+#define twed_intr                      Xtwed_intr
+#define twe_allocate_request           Xtwe_allocate_request
+#define twe_map_request                        Xtwe_map_request
+#define twe_unmap_request              Xtwe_unmap_request
+
+/* public symbols defined in twe_tables.h */
+#define twe_table_status               Xtwe_table_status
+#define twe_table_unitstate            Xtwe_table_unitstate
+#define twe_table_unittype             Xtwe_table_unittype
+#define twe_table_aen                  Xtwe_table_aen
+#define twe_table_opcode               Xtwe_table_opcode
+
+#define TWE_MALLOC_CLASS               M_XTWE
+
+#else /* TWE_OVERRIDE */
+
+#define TWE_MALLOC_CLASS               M_TWE
+
+#endif /* TWE_OVERRIDE */
 
 /* 
  * Wrappers for bus-space actions
  */
 #define TWE_PLATFORM_SOFTC                                                             \
     device_t                   twe_dev;                /* bus device */                \
+    dev_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 */             \
 
 #if defined(__DragonFly__) || __FreeBSD_version < 500003
 # include <machine/clock.h>
+# define INTR_ENTROPY                  0
 
 # include <sys/buf.h>                  /* old buf style */
-# include <sys/proc.h>
-# include <sys/buf2.h>
+# include <sys/buf2.h>                 /* bufq stuff */
+#define FREEBSD_4
 typedef struct buf                     twe_bio;
 typedef struct buf_queue_head          twe_bioq;
 # define TWE_BIO_QINIT(bq)             bufq_init(&bq);
@@ -151,7 +170,7 @@ typedef struct buf_queue_head               twe_bioq;
 # 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_UNIT(bp)              ((struct twed_softc *)(TWE_BIO_SOFTC(bp)))->twed_drive->td_twe_unit
 # 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
@@ -171,7 +190,7 @@ typedef struct bio_queue_head               twe_bioq;
 # define TWE_BIO_LENGTH(bp)            (bp)->bio_bcount
 # define TWE_BIO_LBA(bp)               (bp)->bio_pblkno
 # define TWE_BIO_SOFTC(bp)             (bp)->bio_dev->si_drv1
-# define TWE_BIO_UNIT(bp)              *(int *)((bp)->bio_dev->si_drv2)
+# define TWE_BIO_UNIT(bp)              ((struct twed_softc *)(TWE_BIO_SOFTC(bp)))->twed_drive->td_twe_unit
 # 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
@@ -180,7 +199,7 @@ typedef struct bio_queue_head               twe_bioq;
 # define TWE_BIO_STATS_END(bp)         devstat_end_transaction_bio(&((struct twed_softc *)TWE_BIO_SOFTC(bp))->twed_stats, bp)
 #endif
 
-#endif /* DragonFly */
+#endif /* FreeBSD or DragonFly */
 
 #ifndef TWE_SUPPORTED_PLATFORM
 #error platform not supported
index d0d5dd4..f97ec22 100644 (file)
@@ -1,5 +1,7 @@
 /*-
  * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2003 Paul Saab
+ * Copyright (c) 2003 Vinod Kashyap
  * Copyright (c) 2000 BSDi
  * All rights reserved.
  *
  * 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.2.2.5 2002/03/07 09:57:02 msmith Exp $
- * $DragonFly: src/sys/dev/raid/twe/twe_freebsd.c,v 1.14 2005/06/10 17:10:26 swildner Exp $
+ * $FreeBSD: src/sys/dev/twe/twe_freebsd.c,v 1.2.2.9 2004/06/11 18:57:31 vkashyap Exp $
+ * $DragonFly: src/sys/dev/raid/twe/twe_freebsd.c,v 1.15 2005/08/22 21:16:20 hmp Exp $
  */
 
 /*
  * FreeBSD-specific code.
  */
 
-#include <sys/param.h>
-#include <sys/cons.h>
-#include <machine/bus.h>
-#include <machine/clock.h>
-#include <machine/md_var.h>
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include "twe_compat.h"
-#include "twereg.h"
-#include "tweio.h"
-#include "twevar.h"
-#include "twe_tables.h"
-
-#include <sys/devicestat.h>
+#include <dev/raid/twe/twe_compat.h>
+#include <dev/raid/twe/twereg.h>
+#include <dev/raid/twe/twe_tables.h>
+#include <dev/raid/twe/tweio.h>
+#include <dev/raid/twe/twevar.h>
 
 static devclass_t      twe_devclass;
 
@@ -69,15 +62,12 @@ static      d_open_t                twe_open;
 static d_close_t               twe_close;
 static d_ioctl_t               twe_ioctl_wrapper;
 
-#define TWE_CDEV_MAJOR  146
-
 static struct cdevsw twe_cdevsw = {
-    /* name */ "twe",
-    /* cmaj */ TWE_CDEV_MAJOR,
-    /* flags */        0,
-    /* port */ NULL,
-    /* clone */        NULL,
-
+       "twe",  /* name */
+       TWE_CDEV_MAJOR, /* major number */
+       0,      /* flags */
+       NULL,   /* device port */
+       NULL,   /* cloning */
     twe_open,
     twe_close,
     noread,
@@ -87,7 +77,7 @@ static struct cdevsw twe_cdevsw = {
     nommap,
     nostrategy,
     nodump,
-    nopsize,
+    nopsize
 };
 
 /********************************************************************************
@@ -137,11 +127,16 @@ static int        twe_probe(device_t dev);
 static int     twe_attach(device_t dev);
 static void    twe_free(struct twe_softc *sc);
 static int     twe_detach(device_t dev);
-static void    twe_shutdown(device_t dev);
+static int     twe_shutdown(device_t dev);
 static int     twe_suspend(device_t dev);
 static int     twe_resume(device_t dev);
 static void    twe_pci_intr(void *arg);
 static void    twe_intrhook(void *arg);
+static void    twe_free_request(struct twe_request *tr);
+static void    twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs,
+                                                                 int nsegments, int error);
+static void    twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs,
+                                                                        int nsegments, int error);
 
 static device_method_t twe_methods[] = {
     /* Device interface */
@@ -181,7 +176,7 @@ twe_probe(device_t dev)
     if ((pci_get_vendor(dev) == TWE_VENDOR_ID) &&
        ((pci_get_device(dev) == TWE_DEVICE_ID) || 
         (pci_get_device(dev) == TWE_DEVICE_ID_ASIC))) {
-       device_set_desc(dev, TWE_DEVICE_NAME);
+       device_set_desc(dev, TWE_DEVICE_NAME " driver ver. " TWE_DRIVER_VERSION_STRING);
 #ifdef TWE_OVERRIDE
        return(0);
 #else
@@ -200,7 +195,6 @@ twe_attach(device_t dev)
     struct twe_softc   *sc;
     int                        rid, error;
     u_int32_t          command;
-    dev_t              xdev;
 
     debug_called(4);
 
@@ -219,7 +213,7 @@ twe_attach(device_t dev)
        return (ENXIO);
     }
     SYSCTL_ADD_STRING(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
-       OID_AUTO, "driver_version", CTLFLAG_RD, "$Revision$", 0,
+       OID_AUTO, "driver_version", CTLFLAG_RD, TWE_DRIVER_VERSION_STRING, 0,
        "TWE driver version");
 
     /*
@@ -274,10 +268,7 @@ twe_attach(device_t dev)
        twe_free(sc);
        return(ENXIO);
     }
-    error = bus_setup_intr(sc->twe_dev, sc->twe_irq, 
-                          INTR_TYPE_BIO | INTR_ENTROPY, twe_pci_intr, sc,
-                          &sc->twe_intr, NULL);
-    if (error) {
+    if (bus_setup_intr(sc->twe_dev, sc->twe_irq, INTR_TYPE_BIO | INTR_ENTROPY,  twe_pci_intr, sc, &sc->twe_intr, NULL)) {
        twe_printf(sc, "can't set up interrupt\n");
        twe_free(sc);
        return(ENXIO);
@@ -303,8 +294,10 @@ twe_attach(device_t dev)
     /*
      * Initialise the controller and driver core.
      */
-    if ((error = twe_setup(sc)))
+    if ((error = twe_setup(sc))) {
+       twe_free(sc);
        return(error);
+    }
 
     /*
      * Print some information about the controller and configuration.
@@ -314,12 +307,11 @@ twe_attach(device_t dev)
     /*
      * Create the control device.
      */
-    cdevsw_add(&twe_cdevsw, -1, device_get_unit(sc->twe_dev));
-    xdev = make_dev(&twe_cdevsw, device_get_unit(sc->twe_dev), 
-                           UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, 
-                           "twe%d", device_get_unit(sc->twe_dev));
-    xdev->si_drv1 = sc;
-
+       cdevsw_add(&twe_cdevsw, -1, device_get_unit(sc->twe_dev));
+    sc->twe_dev_t = make_dev(&twe_cdevsw, device_get_unit(sc->twe_dev),
+                       UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "twe%d",
+                       device_get_unit(sc->twe_dev));
+    sc->twe_dev_t->si_drv1 = sc;
     /*
      * Schedule ourselves to bring the controller up once interrupts are available.
      * This isn't strictly necessary, since we disable interrupts while probing the
@@ -328,7 +320,6 @@ twe_attach(device_t dev)
      */
     sc->twe_ich.ich_func = twe_intrhook;
     sc->twe_ich.ich_arg = sc;
-    sc->twe_ich.ich_desc = "twe";
     if (config_intrhook_establish(&sc->twe_ich) != 0) {
        twe_printf(sc, "can't establish configuration hook\n");
        twe_free(sc);
@@ -372,7 +363,10 @@ twe_free(struct twe_softc *sc)
     if (sc->twe_io != NULL)
        bus_release_resource(sc->twe_dev, SYS_RES_IOPORT, TWE_IO_CONFIG_REG, sc->twe_io);
 
-    cdevsw_remove(&twe_cdevsw, -1, device_get_unit(sc->twe_dev));
+       cdevsw_remove(&twe_cdevsw, -1, device_get_unit(sc->twe_dev));
+    /* destroy control device */
+    if (sc->twe_dev_t != (dev_t)NULL)
+       destroy_dev(sc->twe_dev_t);
 
     sysctl_ctx_free(&sc->sysctl_ctx);
 }
@@ -396,7 +390,8 @@ twe_detach(device_t dev)
     /* 
      * Shut the controller down.
      */
-    twe_shutdown(dev);
+    if ((error = twe_shutdown(dev)))
+       goto out;
 
     twe_free(sc);
 
@@ -412,11 +407,11 @@ twe_detach(device_t dev)
  * Note that we can assume that the bioq on the controller is empty, as we won't
  * allow shutdown if any device is open.
  */
-static void
+static int
 twe_shutdown(device_t dev)
 {
     struct twe_softc   *sc = device_get_softc(dev);
-    int                        i;
+    int                        i, error = 0;
 
     debug_called(4);
 
@@ -426,7 +421,9 @@ twe_shutdown(device_t dev)
      * Delete all our child devices.
      */
     for (i = 0; i < TWE_MAX_UNITS; i++) {
-       twe_detach_drive(sc, i);
+      if (sc->twe_drive[i].td_disk != 0)
+       if ((error = twe_detach_drive(sc, i)) != 0)
+           goto out;
     }
 
     /*
@@ -434,7 +431,9 @@ twe_shutdown(device_t dev)
      */
     twe_deinit(sc);
 
+ out:
     crit_exit();
+    return(error);
 }
 
 /********************************************************************************
@@ -502,16 +501,16 @@ twe_intrhook(void *arg)
  *
  * This is called from twe_add_unit.
  */
-void
+int
 twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
 {
     char       buf[80];
-    int                error;
+    int                error = 0;
 
     dr->td_disk =  device_add_child(sc->twe_dev, NULL, -1);
     if (dr->td_disk == NULL) {
-       twe_printf(sc, "device_add_child failed\n");
-       return;
+       twe_printf(sc, "Cannot add unit\n");
+       return (EIO);
     }
     device_set_ivars(dr->td_disk, dr);
 
@@ -520,13 +519,16 @@ twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
      * always set...
      */
     sprintf(buf, "Unit %d, %s, %s",
-           dr->td_unit,
+           dr->td_twe_unit,
            twe_describe_code(twe_table_unittype, dr->td_type),
            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)
-       twe_printf(sc, "bus_generic_attach returned %d\n", error);
+    if ((error = bus_generic_attach(sc->twe_dev)) != 0) {
+       twe_printf(sc, "Cannot attach unit to controller. error = %d\n", error);
+       error = EIO;
+    }
+    return (error);
 }
 
 /********************************************************************************
@@ -534,15 +536,17 @@ twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
  *
  * This is called from twe_del_unit.
  */
-void
+int
 twe_detach_drive(struct twe_softc *sc, int unit)
 {
+    int        error = 0;
 
-    if (sc->twe_drive[unit].td_disk != 0) {
-       if (device_delete_child(sc->twe_dev, sc->twe_drive[unit].td_disk) != 0)
-           twe_printf(sc, "failed to delete unit %d\n", unit);
-       sc->twe_drive[unit].td_disk = 0;
+    if ((error = device_delete_child(sc->twe_dev, sc->twe_drive[unit].td_disk))) {
+       twe_printf(sc, "Cannot delete unit. error = %d\n", error);
+       return (error);
     }
+    bzero(&sc->twe_drive[unit], sizeof(sc->twe_drive[unit]));
+    return (error);
 }
 
 /********************************************************************************
@@ -571,22 +575,6 @@ twe_clear_pci_abort(struct twe_softc *sc)
  ********************************************************************************
  ********************************************************************************/
 
-/*
- * Disk device softc
- */
-struct twed_softc 
-{
-    device_t           twed_dev;
-    dev_t              twed_dev_t;
-    struct twe_softc   *twed_controller;       /* parent device softc */
-    struct twe_drive   *twed_drive;            /* drive data in parent softc */
-    struct disk                twed_disk;              /* generic disk handle */
-    struct devstat     twed_stats;             /* accounting */
-    struct disklabel   twed_label;             /* synthetic label */
-    int                        twed_flags;
-#define TWED_OPEN      (1<<0)                  /* drive is open (can't shut down) */
-};
-
 /*
  * Disk device bus interface
  */
@@ -622,14 +610,12 @@ static    d_close_t       twed_close;
 static d_strategy_t    twed_strategy;
 static d_dump_t        twed_dump;
 
-#define TWED_CDEV_MAJOR        147
-
 static struct cdevsw twed_cdevsw = {
-    "twed",
-    TWED_CDEV_MAJOR,
-    D_DISK,
-    /* port */ NULL,
-    /* clone */ NULL,
+       "twed",
+       TWED_CDEV_MAJOR,
+       D_DISK,
+       /* port */ NULL,
+       /* clone */ NULL,
     twed_open,
     twed_close,
     physread,
@@ -639,9 +625,15 @@ static struct cdevsw twed_cdevsw = {
     nommap,
     twed_strategy,
     twed_dump,
-    nopsize,
+    nopsize
 };
 
+#if 0
+static struct cdevsw   tweddisk_cdevsw;
+#endif
+#ifdef FREEBSD_4
+static int             disks_registered = 0;
+#endif
 
 /********************************************************************************
  * Handle open from generic layer.
@@ -709,7 +701,7 @@ twed_strategy(twe_bio *bp)
     TWED_BIO_IN;
 
     /* bogus disk? */
-    if (sc == NULL) {
+    if ((sc == NULL) || (!sc->twed_drive->td_disk)) {
        TWE_BIO_SET_ERROR(bp, EINVAL);
        printf("twe: bio for invalid disk!\n");
        TWE_BIO_DONE(bp);
@@ -731,17 +723,25 @@ twed_strategy(twe_bio *bp)
 /********************************************************************************
  * System crashdump support
  */
-int
+static int
 twed_dump(dev_t dev, u_int count, u_int blkno, u_int secsize)
 {
     struct twed_softc  *twed_sc = (struct twed_softc *)dev->si_drv1;
     struct twe_softc   *twe_sc  = (struct twe_softc *)twed_sc->twed_controller;
+#if 0
+    u_int              count, blkno, secsize;
+#endif
     vm_paddr_t         addr = 0;
     long               blkcnt;
     int                        dumppages = MAXDUMPPGS;
     int                        error;
     int                        i;
 
+#if 0
+    if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize)))
+        return(error);
+#endif
+
     if (!twed_sc || !twe_sc)
        return(ENXIO);
 
@@ -761,7 +761,7 @@ twed_dump(dev_t dev, u_int count, u_int blkno, u_int secsize)
                va = pmap_kenter_temporary(trunc_page(0), i);
        }
 
-       if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_unit, blkno, va, 
+       if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_twe_unit, blkno, va, 
                                     (PAGE_SIZE * dumppages) / TWE_BLOCK_SIZE)) != 0)
            return(error);
 
@@ -819,6 +819,7 @@ twed_attach(device_t dev)
     parent = device_get_parent(dev);
     sc->twed_controller = (struct twe_softc *)device_get_softc(parent);
     sc->twed_drive = device_get_ivars(dev);
+    sc->twed_drive->td_sys_unit = device_get_unit(dev);
     sc->twed_dev = dev;
 
     /* report the drive */
@@ -826,16 +827,21 @@ twed_attach(device_t dev)
                sc->twed_drive->td_size / ((1024 * 1024) / TWE_BLOCK_SIZE),
                sc->twed_drive->td_size);
     
-    devstat_add_entry(&sc->twed_stats, "twed", device_get_unit(dev), TWE_BLOCK_SIZE,
-                     DEVSTAT_NO_ORDERED_TAGS,
-                     DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 
-                     DEVSTAT_PRIORITY_ARRAY);
+    devstat_add_entry(&sc->twed_stats, "twed", sc->twed_drive->td_sys_unit,
+                       TWE_BLOCK_SIZE,
+                       DEVSTAT_NO_ORDERED_TAGS,
+                       DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 
+                       DEVSTAT_PRIORITY_ARRAY);
 
     /* attach a generic disk device to ourselves */
-    dsk = disk_create(device_get_unit(dev), &sc->twed_disk, 0, &twed_cdevsw);
+    dsk = disk_create(sc->twed_drive->td_sys_unit, &sc->twed_disk,
+                       0, &twed_cdevsw);
     dsk->si_drv1 = sc;
-    dsk->si_drv2 = &sc->twed_drive->td_unit;
+/*    dsk->si_drv2 = sc->twed_drive;*/
     sc->twed_dev_t = dsk;
+#ifdef FREEBSD_4
+    disks_registered++;
+#endif
 
     /* set the maximum I/O size to the theoretical maximum allowed by the S/G list size */
     dsk->si_iosize_max = (TWE_MAX_SGL_LENGTH - 1) * PAGE_SIZE;
@@ -858,6 +864,13 @@ twed_detach(device_t dev)
 
     devstat_remove_entry(&sc->twed_stats);
     disk_destroy(&sc->twed_disk);
+#ifdef FREEBSD_4
+       printf("Disks registered: %d\n", disks_registered);
+#if 0
+    if (--disks_registered == 0)
+       cdevsw_remove(&tweddisk_cdevsw);
+#endif
+#endif
 
     return(0);
 }
@@ -868,19 +881,15 @@ twed_detach(device_t dev)
  ********************************************************************************
  ********************************************************************************/
 
-static void    twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
-static void    twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
-
+MALLOC_DEFINE(TWE_MALLOC_CLASS, "twe commands", "twe commands");
 /********************************************************************************
- * Malloc space for a command buffer.
+ * Allocate a command buffer
  */
-MALLOC_DEFINE(TWE_MALLOC_CLASS, "twe commands", "twe commands");
-
 struct twe_request *
 twe_allocate_request(struct twe_softc *sc)
 {
     struct twe_request *tr;
-    int aligned_size;
+       int aligned_size;
 
     /*
      * TWE requires requests to be 512-byte aligned.  Depend on malloc()
@@ -889,13 +898,15 @@ twe_allocate_request(struct twe_softc *sc)
      * allocator only guarentees same-size alignment for power-of-2 requests.
      */
     aligned_size = (sizeof(struct twe_request) + TWE_ALIGNMASK) &
-                   ~TWE_ALIGNMASK;
+           ~TWE_ALIGNMASK;
     tr = malloc(aligned_size, TWE_MALLOC_CLASS, M_INTWAIT|M_ZERO);
     tr->tr_sc = sc;
     if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_cmdmap)) {
        twe_free_request(tr);
        return(NULL);
     }
+    bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_cmdmap, &tr->tr_command,
+       sizeof(tr->tr_command), twe_setup_request_dmamap, tr, 0);
     if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_dmamap)) {
        bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap);
        twe_free_request(tr);
@@ -907,13 +918,14 @@ twe_allocate_request(struct twe_softc *sc)
 /********************************************************************************
  * Permanently discard a command buffer.
  */
-void
+static void
 twe_free_request(struct twe_request *tr) 
 {
     struct twe_softc   *sc = tr->tr_sc;
     
     debug_called(4);
 
+    bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_cmdmap); 
     bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap);
     bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_dmamap);
     free(tr, TWE_MALLOC_CLASS);
@@ -950,6 +962,13 @@ twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int err
 
     debug_called(4);
 
+    if (tr->tr_flags & TWE_CMD_MAPPED)
+       panic("already mapped command");
+
+    tr->tr_flags |= TWE_CMD_MAPPED;
+
+    if (tr->tr_flags & TWE_CMD_IN_PROGRESS)
+       tr->tr_sc->twe_state &= ~TWE_STATE_FRZN;
     /* save base of first segment in command (applicable if there only one segment) */
     tr->tr_dataphys = segs[0].ds_addr;
 
@@ -995,6 +1014,18 @@ twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int err
            break;
        }
     }
+    if (tr->tr_flags & TWE_CMD_DATAIN)
+       bus_dmamap_sync(tr->tr_sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREREAD);
+    if (tr->tr_flags & TWE_CMD_DATAOUT) {
+       /* if we're using an alignment buffer, and we're writing data, copy the real data out */
+       if (tr->tr_flags & TWE_CMD_ALIGNBUF)
+           bcopy(tr->tr_realdata, tr->tr_data, tr->tr_length);
+       bus_dmamap_sync(tr->tr_sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREWRITE);
+    }
+    if (twe_start(tr) == EBUSY) {
+       tr->tr_sc->twe_state |= TWE_STATE_CTLR_BUSY;
+       twe_requeue_ready(tr);
+    }
 }
 
 static void
@@ -1008,67 +1039,76 @@ twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int
     tr->tr_cmdphys = segs[0].ds_addr;
 }
 
-void
+int
 twe_map_request(struct twe_request *tr)
 {
     struct twe_softc   *sc = tr->tr_sc;
+    int                        error = 0;
 
     debug_called(4);
 
+    if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN)) {
+       twe_requeue_ready(tr);
+       return (EBUSY);
+    }
 
     /*
      * Map the command into bus space.
      */
-    bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_cmdmap, &tr->tr_command, sizeof(tr->tr_command), 
-                   twe_setup_request_dmamap, tr, 0);
     bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_PREWRITE);
 
     /*
      * If the command involves data, map that too.
      */
-    if (tr->tr_data != NULL) {
+    if ((tr->tr_data != NULL) && ((tr->tr_flags & TWE_CMD_MAPPED) == 0)) {
 
        /* 
         * Data must be 512-byte aligned; allocate a fixup buffer if it's not.
         */
        if (((vm_offset_t)tr->tr_data % TWE_ALIGNMENT) != 0) {
-           int aligned_size;
+               int aligned_size;
 
-           aligned_size = (tr->tr_length + TWE_ALIGNMASK) & ~TWE_ALIGNMASK;
-           /* save pointer to 'real' data */
-           tr->tr_realdata = tr->tr_data;
+               aligned_size = (tr->tr_length + TWE_ALIGNMASK) & ~TWE_ALIGNMASK;
+           tr->tr_realdata = tr->tr_data;      /* save pointer to 'real' data */
            tr->tr_flags |= TWE_CMD_ALIGNBUF;
            tr->tr_data = malloc(aligned_size, TWE_MALLOC_CLASS, M_INTWAIT);
+           if (tr->tr_data == NULL) {
+               twe_printf(sc, "%s: malloc failed\n", __func__);
+               tr->tr_data = tr->tr_realdata; /* restore original data pointer */
+               return(ENOMEM);
+           }
        }
        
        /*
         * Map the data buffer into bus space and build the s/g list.
         */
-       bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data, tr->tr_length, 
-                       twe_setup_data_dmamap, tr, 0);
-       if (tr->tr_flags & TWE_CMD_DATAIN)
-           bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREREAD);
-       if (tr->tr_flags & TWE_CMD_DATAOUT) {
-           /* if we're using an alignment buffer, and we're writing data, copy the real data out */
-           if (tr->tr_flags & TWE_CMD_ALIGNBUF)
-               bcopy(tr->tr_realdata, tr->tr_data, tr->tr_length);
-           bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREWRITE);
+       if ((error = bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data,
+                       tr->tr_length, twe_setup_data_dmamap, tr, BUS_DMA_NOWAIT)
+                       == EINPROGRESS)) {
+           tr->tr_flags |= TWE_CMD_IN_PROGRESS;
+           sc->twe_state |= TWE_STATE_FRZN;
+           error = 0;
+       }
+    } else {
+       if ((error = twe_start(tr)) == EBUSY) {
+           sc->twe_state |= TWE_STATE_CTLR_BUSY;
+           twe_requeue_ready(tr);
        }
     }
+
+    return(error);
 }
 
 void
 twe_unmap_request(struct twe_request *tr)
 {
     struct twe_softc   *sc = tr->tr_sc;
-
     debug_called(4);
 
     /*
      * Unmap the command from bus space.
      */
     bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_POSTWRITE);
-    bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_cmdmap); 
 
     /*
      * If the command involved data, unmap that too.
@@ -1095,6 +1135,7 @@ twe_unmap_request(struct twe_request *tr)
 }
 
 #ifdef TWE_DEBUG
+void twe_report(void);
 /********************************************************************************
  * Print current controller status, call from DDB.
  */
index 8e3d31f..13e6c2e 100644 (file)
@@ -1,5 +1,7 @@
 /*-
  * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2003 Paul Saab
+ * Copyright (c) 2003 Vinod Kashyap
  * Copyright (c) 2000 BSDi
  * All rights reserved.
  *
@@ -24,8 +26,8 @@
  * 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.1.2.2 2002/03/07 09:57:02 msmith Exp $
- *     $DragonFly: src/sys/dev/raid/twe/twe_tables.h,v 1.3 2004/01/05 17:40:00 drhodus Exp $
+ *     $FreeBSD: src/sys/dev/twe/twe_tables.h,v 1.1.2.4 2004/04/07 22:18:01 vkashyap Exp $
+ *     $DragonFly: src/sys/dev/raid/twe/twe_tables.h,v 1.4 2005/08/22 21:16:20 hmp Exp $
  */
 
 /*
@@ -36,8 +38,6 @@ struct twe_code_lookup {
     u_int32_t  code;
 };
 
-extern char    *twe_describe_code(struct twe_code_lookup *table, u_int32_t code);
-
 #ifndef TWE_DEFINE_TABLES
 extern struct twe_code_lookup twe_table_status[];
 extern struct twe_code_lookup twe_table_unitstate[];
@@ -46,21 +46,6 @@ extern struct twe_code_lookup twe_table_aen[];
 extern struct twe_code_lookup twe_table_opcode[];
 #else /* TWE_DEFINE_TABLES */
 
-/********************************************************************************
- * Look up a text description of a numeric code and return a pointer to same.
- */
-char *
-twe_describe_code(struct twe_code_lookup *table, u_int32_t code)
-{
-    int                i;
-
-    for (i = 0; table[i].string != NULL; i++)
-       if (table[i].code == code)
-           return(table[i].string);
-    return(table[i+1].string);
-}
-
-
 struct twe_code_lookup twe_table_status[] = {
     /* success */
     {"successful completion",                                  0x00},
@@ -118,7 +103,7 @@ struct twe_code_lookup twe_table_unittype[] = {
 struct twe_code_lookup twe_table_aen[] = {
     {"q queue empty",                  0x00},
     {"q soft reset",                   0x01},
-    {"c degraded mirror",              0x02},
+    {"c degraded unit",                        0x02},
     {"a controller error",             0x03},
     {"c rebuild fail",                 0x04},
     {"c rebuild done",                 0x05},
index 5f5d2cd..6ec5b43 100644 (file)
@@ -1,5 +1,7 @@
 /*-
  * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2003 Paul Saab
+ * Copyright (c) 2003 Vinod Kashyap
  * Copyright (c) 2000 BSDi
  * All rights reserved.
  *
@@ -24,8 +26,8 @@
  * 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.1.2.2 2002/03/07 09:57:02 msmith Exp $
- *     $DragonFly: src/sys/dev/raid/twe/tweio.h,v 1.3 2004/01/05 17:40:00 drhodus Exp $
+ *     $FreeBSD: src/sys/dev/twe/tweio.h,v 1.1.2.4 2004/04/07 22:18:01 vkashyap Exp $
+ *     $DragonFly: src/sys/dev/raid/twe/tweio.h,v 1.4 2005/08/22 21:16:20 hmp Exp $
  */
 
 
@@ -56,6 +58,7 @@ struct twe_usercommand {
 struct twe_qstat {
     u_int32_t  q_length;
     u_int32_t  q_max;
+    u_int32_t  q_min;
 };
 
 /*
@@ -71,8 +74,8 @@ union twe_statrequest {
 /*
  * AEN listen
  */
-#define TWEIO_AEN_POLL         _IOR('T', 102, int)
-#define TWEIO_AEN_WAIT         _IOR('T', 103, int)
+#define TWEIO_AEN_POLL         _IOR('T', 102, u_int16_t)
+#define TWEIO_AEN_WAIT         _IOR('T', 103, u_int16_t)
 
 /*
  * Controller parameter access
index c3934e6..b9bc654 100644 (file)
@@ -1,5 +1,7 @@
 /*-
  * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2003 Paul Saab
+ * Copyright (c) 2003 Vinod Kashyap
  * Copyright (c) 2000 BSDi
  * All rights reserved.
  *
@@ -24,8 +26,8 @@
  * 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.1.2.4 2002/03/07 09:57:02 msmith Exp $
- *      $DragonFly: src/sys/dev/raid/twe/twereg.h,v 1.5 2005/02/11 23:54:10 joerg Exp $
+ *      $FreeBSD: src/sys/dev/twe/twereg.h,v 1.1.2.7 2004/05/12 03:33:37 vkashyap Exp $
+ *     $DragonFly: src/sys/dev/raid/twe/twereg.h,v 1.6 2005/08/22 21:16:20 hmp Exp $
  */
 
 /* 
@@ -162,7 +164,7 @@ typedef struct
 {
     u_int32_t  address;
     u_int32_t  length;
-} TWE_SG_Entry;
+} __attribute__ ((packed)) TWE_SG_Entry;
 
 typedef struct {
     u_int8_t   opcode:5;               /* TWE_OP_INITCONNECTION */
@@ -175,7 +177,7 @@ typedef struct {
     u_int8_t   flags;
     u_int16_t  message_credits;
     u_int32_t  response_queue_pointer;
-} TWE_Command_INITCONNECTION;
+} __attribute__ ((packed)) TWE_Command_INITCONNECTION;
 
 typedef struct
 {
@@ -190,7 +192,7 @@ typedef struct
     u_int16_t  block_count;
     u_int32_t  lba;
     TWE_SG_Entry sgl[TWE_MAX_SGL_LENGTH];
-} TWE_Command_IO;
+} __attribute__ ((packed)) TWE_Command_IO;
 
 typedef struct
 {
@@ -207,7 +209,7 @@ typedef struct
 #define TWE_OP_HOTSWAP_ADD_CBOD                0x01    /* add CBOD to empty port */
 #define TWE_OP_HOTSWAP_ADD_SPARE       0x02    /* add spare to empty port */
     u_int8_t   aport;
-} TWE_Command_HOTSWAP;
+} __attribute__ ((packed)) TWE_Command_HOTSWAP;
 
 typedef struct
 {
@@ -225,7 +227,7 @@ typedef struct
     u_int8_t   feature_mode;
     u_int16_t  all_units;
     u_int16_t  persistence;
-} TWE_Command_SETATAFEATURE;
+} __attribute__ ((packed)) TWE_Command_SETATAFEATURE;
 
 typedef struct
 {
@@ -238,7 +240,7 @@ typedef struct
     u_int8_t   status;
     u_int8_t   flags;
     u_int16_t  target_status;          /* set low byte to target request's ID */
-} TWE_Command_CHECKSTATUS;
+} __attribute__ ((packed)) TWE_Command_CHECKSTATUS;
 
 typedef struct
 {
@@ -252,7 +254,7 @@ typedef struct
     u_int8_t   flags;
     u_int16_t  param_count;
     TWE_SG_Entry sgl[TWE_MAX_SGL_LENGTH];
-} TWE_Command_PARAM;
+} __attribute__ ((packed)) TWE_Command_PARAM;
 
 typedef struct
 {
@@ -271,7 +273,7 @@ typedef struct
 #define TWE_OP_REBUILDUNIT_STARTUNIT   5       /* rebuild src_unit (not supported) */
     u_int8_t   cs:1;                           /* request state change on src_unit */
     u_int8_t   logical_subunit;                /* for RAID10 rebuild of logical subunit */
-} TWE_Command_REBUILDUNIT;
+} __attribute__ ((packed)) TWE_Command_REBUILDUNIT;
 
 typedef struct
 {
@@ -282,6 +284,7 @@ typedef struct
     u_int8_t   unit:4;
     u_int8_t   host_id:4;
     u_int8_t   status;
+    u_int8_t   flags;
     u_int16_t  param;
     u_int16_t  features;
     u_int16_t  sector_count;
@@ -291,7 +294,7 @@ typedef struct
     u_int8_t   drive_head;
     u_int8_t   command;
     TWE_SG_Entry sgl[TWE_MAX_ATA_SGL_LENGTH];
-} TWE_Command_ATA;
+} __attribute__ ((packed)) TWE_Command_ATA;
 
 typedef struct
 {
@@ -309,7 +312,7 @@ typedef struct
 #define TWE_FLAGS_FATAL                0x03
 #define TWE_FLAGS_PERCENTAGE   (1<<8)  /* bits 0-6 indicate completion percentage */
     u_int16_t  count;                  /* block count, parameter count, message credits */
-} TWE_Command_Generic;
+} __attribute__ ((packed)) TWE_Command_Generic;
 
 /* command packet - must be TWE_ALIGNMENT aligned */
 typedef union
@@ -453,7 +456,7 @@ typedef struct
     u_int8_t           log_drv_num;    /* must be zero for configuration == 0x0f */
     u_int32_t          start_lba;
     u_int32_t          block_count;    /* actual drive size if configuration == 0x0f, otherwise less DCB size */
-} TWE_Unit_Descriptor;
+} __attribute__ ((packed)) TWE_Unit_Descriptor;
 
 typedef struct
 {
@@ -461,7 +464,7 @@ typedef struct
     u_int8_t           res1;
     u_int8_t           mirunit_status[4];      /* bitmap of functional subunits in each mirror */
     u_int8_t           res2[6];
-} TWE_Mirror_Descriptor;
+} __attribute__ ((packed)) TWE_Mirror_Descriptor;
 
 typedef struct
 {
@@ -481,14 +484,14 @@ typedef struct
     u_int8_t           log_drv_status; /* bitmap of functional subunits, or mirror units in RAID10 */
     u_int32_t          start_lba;
     u_int32_t          block_count;    /* actual drive size if configuration == 0x0f, otherwise less DCB size */
-    TWE_Unit_Descriptor        subunit[__ARRAY_ZERO];  /* subunit descriptors, in RAID10 mode is [mirunit][subunit] */
-} TWE_Array_Descriptor;
+    TWE_Unit_Descriptor        subunit[0];     /* subunit descriptors, in RAID10 mode is [mirunit][subunit] */
+} __attribute__ ((packed)) TWE_Array_Descriptor;
 
 typedef struct
 {
     u_int16_t  table_id;
     u_int8_t   parameter_id;
     u_int8_t   parameter_size_bytes;
-    u_int8_t   data[__ARRAY_ZERO];
-} TWE_Param;
+    u_int8_t   data[0];
+} __attribute__ ((packed)) TWE_Param;
 
index 5fdabaf..d45465b 100644 (file)
@@ -1,5 +1,7 @@
 /*-
  * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2003 Paul Saab
+ * Copyright (c) 2003 Vinod Kashyap
  * Copyright (c) 2000 BSDi
  * All rights reserved.
  *
  * 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.1.2.4 2002/03/07 09:57:02 msmith Exp $
- *     $DragonFly: src/sys/dev/raid/twe/twevar.h,v 1.4 2005/06/10 17:10:26 swildner Exp $
+ *     $FreeBSD: src/sys/dev/twe/twevar.h,v 1.1.2.8 2004/06/11 18:57:32 vkashyap Exp $
+ *     $DragonFly: src/sys/dev/raid/twe/twevar.h,v 1.5 2005/08/22 21:16:20 hmp Exp $
  */
 
+#define TWE_DRIVER_VERSION_STRING      "1.40.01.002"
+#define TWE_CDEV_MAJOR                 146
+#define TWED_CDEV_MAJOR                        147
+
+
 #ifdef TWE_DEBUG
 #define debug(level, fmt, args...)                                                     \
        do {                                                                            \
@@ -52,7 +59,10 @@ struct twe_drive
     int                        td_cylinders;
     int                        td_heads;
     int                        td_sectors;
-    int                        td_unit;
+    int                        td_sys_unit; /* Unit #, as seen by the system
+                                    (the 0 in twed0, the 1 in twed1 etc.) */
+    int                        td_twe_unit; /* Unit #, as seen by us, and our ctlr
+                                    (index into sc->twe_drive[]) */
 
     /* unit state and type */
     u_int8_t           td_state;
@@ -62,6 +72,22 @@ struct twe_drive
     device_t           td_disk;
 };
 
+/*
+ * Disk device softc
+ */
+struct twed_softc 
+{
+    device_t           twed_dev;
+    dev_t              twed_dev_t;
+    struct twe_softc   *twed_controller;       /* parent device softc */
+    struct twe_drive   *twed_drive;            /* drive data in parent softc */
+    struct disk                twed_disk;              /* generic disk handle */
+    struct devstat     twed_stats;             /* accounting */
+    struct disklabel   twed_label;             /* synthetic label */
+    int                        twed_flags;
+#define TWED_OPEN      (1<<0)                  /* drive is open (can't shut down) */
+};
+
 /*
  * Per-command control structure.
  *
@@ -85,11 +111,14 @@ struct twe_request
 #define TWE_CMD_SETUP          0       /* being assembled */
 #define TWE_CMD_BUSY           1       /* submitted to controller */
 #define TWE_CMD_COMPLETE       2       /* completed by controller (maybe with error) */
+#define TWE_CMD_ERROR          3       /* encountered error, even before submission to controller */
     int                                tr_flags;
 #define TWE_CMD_DATAIN         (1<<0)
 #define TWE_CMD_DATAOUT                (1<<1)
 #define TWE_CMD_ALIGNBUF       (1<<2)  /* data in bio is misaligned, have to copy to/from private buffer */
 #define TWE_CMD_SLEEPER                (1<<3)  /* owner is sleeping on this command */
+#define TWE_CMD_MAPPED         (1<<4)  /* cmd has been mapped */
+#define TWE_CMD_IN_PROGRESS    (1<<5)  /* bus_dmamap_load returned EINPROGRESS */
     void                       (* tr_complete)(struct twe_request *tr);        /* completion handler */
     void                       *tr_private;    /* submitter-private data or wait channel */
 
@@ -121,6 +150,8 @@ struct twe_softc
 #define TWE_STATE_SHUTDOWN     (1<<1)  /* controller is shut down */
 #define TWE_STATE_OPEN         (1<<2)  /* control device is open */
 #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 */
     int                        twe_host_id;
     struct twe_qstat   twe_qstat[TWEQ_COUNT];  /* queue statistics */
 
@@ -135,25 +166,26 @@ extern void       twe_init(struct twe_softc *sc);                 /* init controller */
 extern void    twe_deinit(struct twe_softc *sc);               /* stop controller */
 extern void    twe_intr(struct twe_softc *sc);                 /* hardware interrupt signalled */
 extern void    twe_startio(struct twe_softc *sc);
+extern int     twe_start(struct twe_request *tr);
 extern int     twe_dump_blocks(struct twe_softc *sc, int unit, /* crashdump block write */
                                u_int32_t lba, void *data, int nblks);
 extern int     twe_ioctl(struct twe_softc *sc, int cmd,
                                  void *addr);                  /* handle user request */
 extern void    twe_describe_controller(struct twe_softc *sc);  /* print controller info */
+extern char    *twe_describe_code(struct twe_code_lookup *table, u_int32_t code);
 extern void    twe_print_controller(struct twe_softc *sc);
 extern void    twe_enable_interrupts(struct twe_softc *sc);    /* enable controller interrupts */
 extern void    twe_disable_interrupts(struct twe_softc *sc);   /* disable controller interrupts */
 
-extern void    twe_attach_drive(struct twe_softc *sc,
-                                        struct twe_drive *dr); /* attach drive when found in twe_add_unit */
-extern void    twe_detach_drive(struct twe_softc *sc,
+extern int     twe_attach_drive(struct twe_softc *sc,
+                                        struct twe_drive *dr); /* attach drive when found in twe_init */
+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 struct twe_request *twe_allocate_request(struct twe_softc *sc); /* allocate request structure */
-extern void    twe_free_request(struct twe_request *tr);       /* free request structure */
-extern void    twe_map_request(struct twe_request *tr);        /* make request visible to controller, do s/g */
+extern struct  twe_request *twe_allocate_request(struct twe_softc *sc);/* allocate request structure */
+extern int     twe_map_request(struct twe_request *tr);        /* make request visible to controller, do s/g */
 extern void    twe_unmap_request(struct twe_request *tr);      /* cleanup after transfer, unmap */
 
 /********************************************************************************
@@ -168,11 +200,20 @@ extern void       twe_unmap_request(struct twe_request *tr);      /* cleanup after transfer
                qs->q_max = qs->q_length;                       \
        } while(0)
 
-#define TWEQ_REMOVE(sc, qname)    (sc)->twe_qstat[qname].q_length--
-#define TWEQ_INIT(sc, qname)                   \
-       do {                                    \
-           sc->twe_qstat[qname].q_length = 0;  \
-           sc->twe_qstat[qname].q_max = 0;     \
+#define TWEQ_REMOVE(sc, qname)                                 \
+       do {                                                    \
+           struct twe_qstat *qs = &(sc)->twe_qstat[qname];     \
+                                                               \
+           qs->q_length--;                                     \
+           if (qs->q_length < qs->q_min)                       \
+               qs->q_min = qs->q_length;                       \
+       } while(0)
+
+#define TWEQ_INIT(sc, qname)                           \
+       do {                                            \
+           sc->twe_qstat[qname].q_length = 0;          \
+           sc->twe_qstat[qname].q_max = 0;             \
+           sc->twe_qstat[qname].q_min = 0xFFFFFFFF;    \
        } while(0)