--- //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-17 08:59:10.000000000 0000 @@ -68,7 +68,7 @@ /* * 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); @@ -388,7 +388,7 @@ 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); }; /******************************************************************************** @@ -996,7 +996,7 @@ /* 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); @@ -1104,7 +1104,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,13 +1122,16 @@ * XXX it might be more efficient to return EBUSY immediately * and let the command be rescheduled. */ - for (i = 100000; (i > 0); i--) { + first = 1; + for (i = 100000; i > 0; i--) { /* check to see if we can post a command */ status_reg = TWE_STATUS(sc); 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 +1147,11 @@ } #endif return(0); + } else if (!(status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY) && i > 1) + twe_done(sc, 0); + if (first) { + sc->twe_spinwaits++; + first = 0; } } @@ -1162,7 +1170,7 @@ * 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; @@ -1180,6 +1188,8 @@ if (!(status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY)) { found = 1; + if (!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 +1208,7 @@ } /* if we've completed any commands, try posting some more */ - if (found) + if (found && startio) twe_startio(sc); /* handle completion and timeouts */ @@ -1768,7 +1778,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 +1794,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-17 08:59:10.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,12 @@ #define TWE_STATE_FRZN (1<<4) /* got EINPROGRESS */ #define TWE_STATE_CTLR_BUSY (1<<5) /* controller cmd queue full */ #define TWE_STATE_DETACHING (1<<6) /* controller is being shut down */ + int twe_host_id; struct twe_qstat twe_qstat[TWEQ_COUNT]; /* queue statistics */ + int twe_spinwaits; + int twe_spincompl; + int twe_spindone; TWE_PLATFORM_SOFTC /* platform-specific softc elements */ };