return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
}
-static bool tcm_loop_flush_work_iter(struct request *rq, void *data)
-{
- struct scsi_cmnd *sc = blk_mq_rq_to_pdu(rq);
- struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc);
- struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd;
-
- flush_work(&se_cmd->work);
- return true;
-}
-
-static int tcm_loop_target_reset(struct scsi_cmnd *sc)
-{
- struct tcm_loop_hba *tl_hba;
- struct tcm_loop_tpg *tl_tpg;
- struct Scsi_Host *sh = sc->device->host;
- int ret;
-
- /*
- * Locate the tcm_loop_hba_t pointer
- */
- tl_hba = *(struct tcm_loop_hba **)shost_priv(sh);
- if (!tl_hba) {
- pr_err("Unable to perform device reset without active I_T Nexus\n");
- return FAILED;
- }
- /*
- * Locate the tl_tpg pointer from TargetID in sc->device->id
- */
- tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
- if (!tl_tpg)
- return FAILED;
-
- /*
- * Issue a LUN_RESET to drain all commands that the target core
- * knows about. This handles commands not yet marked CMD_T_COMPLETE.
- */
- ret = tcm_loop_issue_tmr(tl_tpg, sc->device->lun, 0, TMR_LUN_RESET);
- if (ret != TMR_FUNCTION_COMPLETE)
- return FAILED;
-
- /*
- * Flush any deferred target core completion work that may still be
- * queued. Commands that already had CMD_T_COMPLETE set before the TMR
- * are skipped by the TMR drain, but their async completion work
- * (transport_lun_remove_cmd → percpu_ref_put, release_cmd → scsi_done)
- * may still be pending in target_completion_wq.
- *
- * The SCSI EH will reuse in-flight scsi_cmnd structures for recovery
- * commands (e.g. TUR) immediately after this handler returns SUCCESS —
- * if deferred work is still pending, the memset in queuecommand would
- * zero the se_cmd while the work accesses it, leaking the LUN
- * percpu_ref and hanging configfs unlink forever.
- *
- * Use blk_mq_tagset_busy_iter() to find all started requests and
- * flush_work() on each — the same pattern used by mpi3mr, scsi_debug,
- * and other SCSI drivers to drain outstanding commands during reset.
- */
- blk_mq_tagset_busy_iter(&sh->tag_set, tcm_loop_flush_work_iter, NULL);
-
- tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE;
- return SUCCESS;
-}
-
static const struct scsi_host_template tcm_loop_driver_template = {
.show_info = tcm_loop_show_info,
.proc_name = "tcm_loopback",
.change_queue_depth = scsi_change_queue_depth,
.eh_abort_handler = tcm_loop_abort_task,
.eh_device_reset_handler = tcm_loop_device_reset,
- .eh_target_reset_handler = tcm_loop_target_reset,
.this_id = -1,
.sg_tablesize = 256,
.max_sectors = 0xFFFF,