Simple evaluation of the response uis result codes Signed-off-by: Oliver Neukum <oneukum@xxxxxxxx> --- drivers/usb/storage/uas.c | 80 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 843c73e..d2d9244 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -57,7 +57,7 @@ struct uas_dev_info { spinlock_t lock; struct work_struct work; struct completion deathknell; - bool aborted; /* a reply to a TASK ABORT was seen */ + bool tmf_perfomed; /* an ack to a TMF was seen */ bool tmf_catastrophic; /* TMF failed, retry useless */ bool tmf_error; /* tmf may be retried after error handling */ }; @@ -271,9 +271,9 @@ static void finish_tmf(struct uas_dev_info *devinfo, struct response_iu *riu, st uas_log_cmd_state(cmnd, "expected response iu", response_code); if (response_code == RC_TMF_SUCCEEDED) - devinfo->aborted = true; + devinfo->tmf_perfomed = true; else - devinfo->aborted = false; + devinfo->tmf_perfomed = false; } static bool uas_evaluate_response_iu(struct response_iu *riu, struct scsi_cmnd *cmnd) @@ -796,6 +796,35 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, static DEF_SCSI_QCMD(uas_queuecommand) +static void prepare_tmf_urb(struct uas_dev_info *devinfo, struct scsi_cmnd *cmnd) +{ + usb_fill_bulk_urb(devinfo->management_urb, + devinfo->udev, + devinfo->cmd_pipe, /* shared */ + devinfo->tmf_iu, + sizeof(devinfo->tmf_iu), + uas_tmf_cmplt, + cmnd->device->host); +} + +static void prepare_ABORT_TASK_tmf(struct task_mgmt_iu *tmf, struct uas_cmd_info *cmdinfo) +{ + memset(tmf, 0, sizeof(struct task_mgmt_iu)); + tmf->iu_id = IU_ID_TASK_MGMT; + tmf->tag = cpu_to_be16( TAG_FOR_TMF ); + tmf->function = TMF_ABORT_TASK; + tmf->task_tag = cmdinfo->uas_tag; /* already BE */ +} + +static void prepare_LOGICAL_UNIT_RESET_tmf(struct task_mgmt_iu *tmf, struct scsi_device *sdev) +{ + memset(tmf, 0, sizeof(struct task_mgmt_iu)); + tmf->iu_id = IU_ID_TASK_MGMT; + tmf->tag = cpu_to_be16( TAG_FOR_TMF ); + tmf->function = TMF_LOGICAL_UNIT_RESET; + int_to_scsilun(sdev->lun, &tmf->lun); +} + /* * For now we do not support actually sending an abort to the device, so * this eh always fails. Still we must define it to make sure that we've @@ -823,17 +852,9 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) devinfo->deathrow = cmnd; devinfo->tmf_catastrophic = false; devinfo->tmf_error = false; - usb_fill_bulk_urb(devinfo->management_urb, - devinfo->udev, - devinfo->cmd_pipe, /* shared */ - devinfo->tmf_iu, - sizeof(devinfo->tmf_iu), - uas_tmf_cmplt, - cmnd->device->host); - tmf->iu_id = IU_ID_TASK_MGMT; - tmf->tag = cpu_to_be16( TAG_FOR_TMF ); - tmf->function = TMF_ABORT_TASK; - tmf->task_tag = cmdinfo->uas_tag; /* already BE */ + + prepare_tmf_urb(devinfo, cmnd); + prepare_ABORT_TASK_tmf(tmf, cmdinfo); err = usb_submit_urb(devinfo->management_urb, GFP_NOIO); if (err < 0) /* unkillable */ @@ -848,7 +869,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) time = wait_for_completion_timeout(&devinfo->deathknell, USB_CTRL_GET_TIMEOUT); /* in case of timeout */ usb_kill_urb(devinfo->management_urb); - if (time && devinfo->aborted) { + if (time && devinfo->tmf_perfomed) { cmdinfo->state &= ~COMMAND_ABORTING; /* * manually finish as resources must be freed only once @@ -886,6 +907,34 @@ give_up: return success; } +static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd) +{ + struct scsi_device *sdev = cmnd->device; + struct uas_dev_info *devinfo = sdev->hostdata; + struct task_mgmt_iu *tmf = devinfo->tmf_iu; + int success = FAILED; + int err; + int time; + + devinfo->tmf_catastrophic = false; + devinfo->tmf_error = false; + init_completion(&devinfo->deathknell); + prepare_tmf_urb(devinfo, cmnd); + prepare_LOGICAL_UNIT_RESET_tmf(tmf, cmnd->device); + + err = usb_submit_urb(devinfo->management_urb, GFP_NOIO); + if (err < 0) + goto failure; + + time = wait_for_completion_timeout(&devinfo->deathknell, USB_CTRL_GET_TIMEOUT); + if (time && devinfo->tmf_perfomed) + success = SUCCESS; + usb_kill_urb(devinfo->management_urb); + +failure: + return success; +} + static int uas_eh_host_reset_handler(struct scsi_cmnd *cmnd) { struct scsi_device *sdev = cmnd->device; @@ -990,6 +1039,7 @@ static struct scsi_host_template uas_host_template = { .slave_alloc = uas_slave_alloc, .slave_configure = uas_slave_configure, .eh_abort_handler = uas_eh_abort_handler, + .eh_device_reset_handler = uas_eh_device_reset_handler, .eh_host_reset_handler = uas_eh_host_reset_handler, .can_queue = 65536, /* Is there a limit on the _host_ ? */ .this_id = -1, -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html