>one way to trip that for > your testing is to send a SCSI command that is going > to take some time (e.g. a READ of thousands of blocks > should take some time, even on flash) and setup the > command timeout to zero seconds and or close as you can to > zero. Actually I am registering my task management functions to scsi_transport_template. I am handling all my task management functions in eh_strategy_handler. Whare as in eh_timed_out I am just completing the request. Here I am pasting the the code I have with me. struct scsi_transport_template * uas_domain_attach_transport(struct uas_domain_function_template *dft) { struct scsi_transport_template *stt = uas_attach_transport(); struct uas_internal *i; PRINTK("<%s> <%s> Entry!\n",__FILE__, __FUNCTION__); if (!stt) return stt; i = to_uas_internal(stt); i->dft = dft; stt->create_work_queue = 1; stt->eh_timed_out = uas_scsi_timed_out; stt->eh_strategy_handler = uas_scsi_recover_host; PRINTK("<%s> <%s> Exit!\n",__FILE__, __FUNCTION__); return stt; } void uas_scsi_recover_host(struct Scsi_Host *shost) { struct us_data *us = host_to_us(shost); unsigned long flags; LIST_HEAD(eh_work_q); spin_lock_irqsave(shost->host_lock, flags); list_splice_init(&shost->eh_cmd_q, &eh_work_q); spin_unlock_irqrestore(shost->host_lock, flags); PRINTK("<%s> <%s> Entry!\n",__FILE__, __FUNCTION__); if (uas_eh_handle_uas_errors(shost, &eh_work_q, &us->eh_done_q)) goto out; if (!scsi_eh_get_sense(&eh_work_q, &us->eh_done_q)) scsi_eh_ready_devs(shost, &eh_work_q, &us->eh_done_q); out: scsi_eh_flush_done_q(&us->eh_done_q); PRINTK("<%s> <%s> Exit!\n",__FILE__, __FUNCTION__); return; } static int uas_eh_handle_uas_errors(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q) { struct scsi_cmnd *cmd, *n; enum task_disposition res = TASK_IS_DONE; int tmf_resp, need_reset; unsigned long flags; struct us_data *us = host_to_us(shost); PRINTK("<%s> <%s> Entry!\n",__FILE__, __FUNCTION__); Again: list_for_each_entry_safe(cmd, n, work_q, eh_entry) { struct uas_task *task = TO_UAS_TASK(cmd); if (!task) continue; list_del_init(&cmd->eh_entry); spin_lock_irqsave(&task->task_state_lock, flags); need_reset = task->task_state_flags & UAS_TASK_NEED_DEV_RESET; spin_unlock_irqrestore(&task->task_state_lock, flags); if (need_reset) { PRINTK("%s: task 0x%p requests reset\n", __func__, task); goto reset; } PRINTK("trying to find task 0x%p\n", task); res = uas_scsi_find_task(task, us); cmd->eh_eflags = 0; switch (res) { case TASK_IS_DONE: PRINTK("%s: task 0x%p is done\n", __func__, task); uas_eh_finish_cmd(cmd); continue; case TASK_IS_ABORTED: PRINTK("%s: task 0x%p is aborted\n", __func__, task); uas_eh_finish_cmd(cmd); continue; case TASK_IS_AT_LU: PRINTK("task 0x%p is at LU: lu recover\n", task); reset: tmf_resp = uas_recover_lu(us, cmd); if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { PRINTK("LU %x is " "recovered\n", cmd->device->lun); uas_eh_finish_cmd(cmd); uas_scsi_clear_queue_lu(work_q, cmd); goto Again; } /* fallthrough */ case TASK_IS_NOT_AT_LU: case TASK_ABORT_FAILED: PRINTK("task 0x%p is not at LU: I_T recover\n", task); tmf_resp = uas_recover_I_T(us); if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { uas_eh_finish_cmd(cmd); uas_scsi_clear_queue_I_T(work_q, us); goto Again; } /* Hammer time :-) */ try_to_reset_cmd_device(cmd); /* If we are here -- this means that no amount * of effort could recover from errors. Quite * possibly the HA just disappeared. */ PRINTK("error from device LUN %x " "couldn't be recovered in any way\n", cmd->device->lun); uas_eh_finish_cmd(cmd); goto clear_q; } } return list_empty(work_q); clear_q: PRINTK("--- Exit %s -- clear_q\n", __func__); list_for_each_entry_safe(cmd, n, work_q, eh_entry) uas_eh_finish_cmd(cmd); PRINTK("<%s> <%s> Exit!\n",__FILE__, __FUNCTION__); return list_empty(work_q); } enum blk_eh_timer_return uas_scsi_timed_out(struct scsi_cmnd *cmd) { struct uas_task *task = TO_UAS_TASK(cmd); unsigned long flags; if (!task) { cmd->request->timeout /= 2; PRINTK("command 0x%p, task 0x%p, gone: %s\n", cmd, task, (cmd->request->timeout ? "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED")); if (!cmd->request->timeout) return BLK_EH_NOT_HANDLED; return BLK_EH_RESET_TIMER; } spin_lock_irqsave(&task->task_state_lock, flags); BUG_ON(task->task_state_flags & UAS_TASK_STATE_ABORTED); if (task->task_state_flags & UAS_TASK_STATE_DONE) { spin_unlock_irqrestore(&task->task_state_lock, flags); PRINTK("command 0x%p, task 0x%p, timed out: " "BLK_EH_HANDLED\n", cmd, task); return BLK_EH_HANDLED; } if (!(task->task_state_flags & UAS_TASK_AT_INITIATOR)) { spin_unlock_irqrestore(&task->task_state_lock, flags); PRINTK("command 0x%p, task 0x%p, not at initiator: " "BLK_EH_RESET_TIMER\n", cmd, task); return BLK_EH_RESET_TIMER; } task->task_state_flags |= UAS_TASK_STATE_ABORTED; spin_unlock_irqrestore(&task->task_state_lock, flags); PRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n", cmd, task); PRINTK("<%s> <%s> Exit!\n",__FILE__, __FUNCTION__); return BLK_EH_NOT_HANDLED; } -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html