--- a/sys/dev/raid/tws/tws_hdm.c +++ b/sys/dev/raid/tws/tws_hdm.c @@ -77,6 +77,7 @@ void tws_enable_db_intr(struct tws_softc *sc); void tws_aen_synctime_with_host(struct tws_softc *sc); void tws_init_obfl_q(struct tws_softc *sc); +void tws_reset_obfl_q(struct tws_softc *sc); void tws_display_ctlr_info(struct tws_softc *sc); int @@ -147,6 +148,27 @@ sc->obfl_q_overrun = false; } + +/* + * DF-4841: a controller soft reset wipes the firmware's copy of the + * outbound free list, but sc->sense_bufs[i].posted still says every frame + * is queued. Clear the flags on the reset path BEFORE tws_init_obfl_q() + * re-runs, otherwise the "refill" posts nothing and the firmware is left + * with zero response frames (every post-reset I/O times out forever). + * (Do NOT clear inside tws_init_obfl_q() itself: its other caller, + * tws_submit_command() on OBFL overrun, must not double-post frames that + * are still queued.) + */ +void +tws_reset_obfl_q(struct tws_softc *sc) +{ + int i; + + TWS_TRACE_DEBUG(sc, "reset obfl q", 0, 0); + for ( i=0; i < tws_queue_depth; i++ ) + sc->sense_bufs[i].posted = false; +} + int tws_init_connect(struct tws_softc *sc, u_int16_t mcreadits ) { --- a/sys/dev/raid/tws/tws_cam.c +++ b/sys/dev/raid/tws/tws_cam.c @@ -120,6 +120,7 @@ struct tws_circular_q *cq, struct tws_event_packet *aen); extern int tws_use_32bit_sgls; extern boolean tws_ctlr_reset(struct tws_softc *sc); +extern void tws_reset_obfl_q(struct tws_softc *sc); extern struct tws_request * tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type ); extern void tws_turn_off_interrupts(struct tws_softc *sc); @@ -1260,6 +1261,7 @@ timeout_val=0; try = 2; sc->obfl_q_overrun = false; + tws_reset_obfl_q(sc); if ( tws_init_connect(sc, tws_queue_depth) ) { TWS_TRACE_DEBUG(sc, "initConnect failed", 0, sc->is64bit); }