Simple evaluation of the response uis result codes

Signed-off-by: Oliver Neukum <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to