--- a/sys/dev/raid/twa/tw_cl_misc.c +++ b/sys/dev/raid/twa/tw_cl_misc.c @@ -380,6 +380,19 @@ if (req) { if (req->data) ctlr->internal_req_busy = TW_CL_FALSE; + + /* + * DF-4509: on ETIMEDOUT (or any break while the firmware + * still owns the request), req is still linked in + * TW_CLI_BUSY_Q or TW_CLI_PENDING_Q. Unlink it before + * returning it to the free queue, or it ends up with + * membership in two queues and is handed out twice. + */ + if (req->state == TW_CLI_REQ_STATE_BUSY) + tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q); + else if (req->state == TW_CLI_REQ_STATE_PENDING) + tw_cli_req_q_remove_item(req, TW_CLI_PENDING_Q); + tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); } return(error);