--- //depot/vendor/freebsd/src/sys/dev/twe/twe.c 2012-08-13 21:30:34.000000000 0000 +++ //depot/user/jhb/cleanup/sys/dev/twe/twe.c 2012-08-14 13:58:43.000000000 0000 @@ -410,6 +410,9 @@ return; /* spin until something prevents us from doing any work */ + KASSERT(!(sc->twe_state & TWE_STATE_IN_STARTIO), + ("nested call to twe_startio()")); + sc->twe_state |= TWE_STATE_IN_STARTIO; for (;;) { /* try to get a command that's already ready to go */ @@ -470,6 +473,7 @@ wakeup_one(tr); /* wakeup the sleeping owner */ } } + sc->twe_state &= ~TWE_STATE_IN_STARTIO; } /******************************************************************************** @@ -1104,7 +1108,7 @@ { struct twe_softc *sc = tr->tr_sc; TWE_Command *cmd; - int i; + int first, i; u_int32_t status_reg; debug_called(4); @@ -1122,6 +1126,7 @@ * XXX it might be more efficient to return EBUSY immediately * and let the command be rescheduled. */ + first = 1; for (i = 100000; (i > 0); i--) { /* check to see if we can post a command */ @@ -1129,6 +1134,8 @@ twe_check_bits(sc, status_reg); if (!(status_reg & TWE_STATUS_COMMAND_QUEUE_FULL)) { + if (!first) + sc->twe_spincompl++; twe_enqueue_busy(tr); TWE_COMMAND_QUEUE(sc, TWE_FIND_COMMANDPHYS(tr)); @@ -1144,6 +1151,11 @@ } #endif return(0); + } else if (!(status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY)) + twe_done(sc); + if (first) { + sc->twe_spinwaits++; + first = 0; } } @@ -1180,6 +1192,8 @@ if (!(status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY)) { found = 1; + if (sc->twe_state & TWE_STATE_IN_STARTIO) + sc->twe_spindone++; rq = TWE_RESPONSE_QUEUE(sc); tr = sc->twe_lookup[rq.u.response_id]; /* find command */ cmd = TWE_FIND_COMMAND(tr); @@ -1198,7 +1212,7 @@ } /* if we've completed any commands, try posting some more */ - if (found) + if (found && !(sc->twe_state & TWE_STATE_IN_STARTIO)) twe_startio(sc); /* handle completion and timeouts */ @@ -1768,7 +1782,6 @@ static char * twe_format_aen(struct twe_softc *sc, u_int16_t aen) { - static char buf[80]; device_t child; char *code, *msg; @@ -1785,25 +1798,28 @@ 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); } /******************************************************************************** --- //depot/vendor/freebsd/src/sys/dev/twe/twe_freebsd.c 2012-08-13 21:30:34.000000000 0000 +++ //depot/user/jhb/cleanup/sys/dev/twe/twe_freebsd.c 2012-08-14 13:56:54.000000000 0000 @@ -179,7 +179,7 @@ twe_attach(device_t dev) { struct twe_softc *sc; - struct sysctl_oid *sysctl_tree; + struct sysctl_oid *sysctl_tree, *spin_tree; int rid, error; debug_called(4); @@ -209,6 +209,19 @@ OID_AUTO, "driver_version", CTLFLAG_RD, TWE_DRIVER_VERSION_STRING, 0, "TWE driver version"); + spin_tree = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "spin", CTLFLAG_RD, 0, + "twe_start() spin statistics"); + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(spin_tree), + OID_AUTO, "waits", CTLFLAG_RD, &sc->twe_spinwaits, 0, + "Commands that encountered a busy command queue and had to wait"); + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(spin_tree), + OID_AUTO, "compl", CTLFLAG_RD, &sc->twe_spincompl, 0, + "Commands that eventually completed after having to wait"); + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(spin_tree), + OID_AUTO, "done", CTLFLAG_RD, &sc->twe_spinwaits, 0, + "Commands completed while waiting to enqueue another command"); + /* * Force the busmaster enable bit on, in case the BIOS forgot. */ --- //depot/vendor/freebsd/src/sys/dev/twe/twevar.h 2012-08-13 21:30:34.000000000 0000 +++ //depot/user/jhb/cleanup/sys/dev/twe/twevar.h 2012-08-14 13:56:54.000000000 0000 @@ -125,6 +125,7 @@ u_int16_t twe_aen_queue[TWE_Q_LENGTH]; /* AENs queued for userland tool(s) */ int twe_aen_head, twe_aen_tail; /* ringbuffer pointers for AEN queue */ int twe_wait_aen; /* wait-for-aen notification */ + char twe_aen_buf[80]; /* AEN format buffer */ /* controller status */ int twe_state; @@ -135,8 +136,13 @@ #define TWE_STATE_FRZN (1<<4) /* got EINPROGRESS */ #define TWE_STATE_CTLR_BUSY (1<<5) /* controller cmd queue full */ #define TWE_STATE_DETACHING (1<<6) /* controller is being shut down */ +#define TWE_STATE_IN_STARTIO (1<<7) /* prevent twe_startio() recursion */ + int twe_host_id; struct twe_qstat twe_qstat[TWEQ_COUNT]; /* queue statistics */ + int twe_spinwaits; + int twe_spincompl; + int twe_spindone; TWE_PLATFORM_SOFTC /* platform-specific softc elements */ };