/**
 * @file hv_drv_UsbStorageTransport.c
 * @brief This is usb driver for usb storage transport.
 * @details 
 * @author HiView SoC Software Team
 * @version 0.0.1
 * @date 20230417
 * @copyright Copyright(c),2022-9, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                         <th>Date             <th>Details
 * <tr><td>HiView SoC Software Team   <td>20230417       <td>Create and first Version.
 * </table>
 **/


#include "hv_drv_UsbCoreUsb.h"
#include "hv_drv_UsbCoreHcd.h"
#include "hv_drv_UsbCoreHub.h"
#include "hv_drv_UsbStorageTransport.h"
#include "hv_drv_UsbStorage.h"
#include "hv_drv_UsbStorageUmass.h"
#include "hv_drv_UsbCoreQuirks.h"
#include "hv_drv_UsbBitWise.h"


static void usb_stor_blocking_completion(struct urb *urb) {
    completion_complete((completion *) urb->context);
}

/* This is the common part of the URB message submission code
 *
 * All URBs from the usb-storage driver involved in handling a queued scsi
 * command _must_ pass through this function (or something like it) for the
 * abort mechanisms to work properly.
 */
void musb_irq_handler(u32 interruptId, void *param);
static int usb_stor_msg_common(struct us_data *us,
                               struct urb *urb, unsigned int timeout) {
    completion done;
    boolean waited;
    int status;
    int expire;

    /* don't submit URBs during abort processing */
    if (test_bit(US_FLIDX_ABORTING, &us->dflags))
        return -EIO;

    done.isr_caller = is_root_hub(urb->dev)?0:1;
    init_completion(&done);

    urb->context = &done;
    urb->actual_length = 0;

    status = usb_submit_urb(urb);
    if (status) {
        goto done;
    }

    /* since the URB has been submitted successfully, it's now okay
    * to cancel it */
    set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);

    /* did an abort occur during the submission? */
    if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {

        /* cancel the URB, if it hasn't been cancelled already */
        if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
            usb_unlink_urb(urb);
        }
    }

    /* wait for the completion of the URB */
    expire = timeout ? timeout : 300;
    waited = wait_for_completion_timeout(&done, expire);

    status = urb->status;
    clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
    if (waited) {
        status = usb_kill_urb(urb);
    }

done:
    destroy_complete(&done);

    return status;
}

/*
 * Transfer one control message, with timeouts, and allowing early
 * termination.  Return codes are usual -Exxx, *not* USB_STOR_XFER_xxx.
 */
int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
                         u8 request, u8 requesttype, u16 value, u16 index,
                         void *data, u16 size, unsigned int timeout) {
    int status;
    HANDLE sc;
    us->cr.bRequestType = requesttype;
    us->cr.bRequest = request;
    us->cr.wValue = (value);
    us->cr.wIndex = (index);
    us->cr.wLength = (size);

    us->current_urb->transfer_flags = 0;
    usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe,
                         (unsigned char*) (&us->cr), data, size,
                         usb_stor_blocking_completion, NULL);
    status = usb_stor_msg_common(us, us->current_urb, timeout);

    sc = spin_lock_irq();
    if (status == 0)
        status = us->current_urb->actual_length;
    spin_unlock_irq(sc);
    return status;
}

/* This is a version of usb_clear_halt() that allows early termination and
 * doesn't read the status from the device -- this is because some devices
 * crash their internal firmware when the status is requested after a halt.
 *
 * A definitive list of these 'bad' devices is too difficult to maintain or
 * make complete enough to be useful.  This problem was first observed on the
 * Hagiwara FlashGate DUAL unit.  However, bus traces reveal that neither
 * MacOS nor Windows checks the status after clearing a halt.
 *
 * Since many vendors in this space limit their testing to interoperability
 * with these two OSes, specification violations like this one are common.
 */
int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) {
    int result;
    int endp = usb_pipeendpoint(pipe);

    if (usb_pipein(pipe))
        endp |= USB_DIR_IN;

    result = usb_stor_control_msg(us, us->send_ctrl_pipe,
                                  USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
                                  USB_ENDPOINT_HALT, endp,
                                  NULL, 0, 3*100);

    if (result >= 0) {
        usb_reset_endpoint(us->pusb_dev, endp);
    } else {
        USB_LOGE("%s, result = %d\n", __FUNCTION__, result);
    }

    return result;
}

/*
 * Interpret the results of a URB transfer
 *
 * This function prints appropriate debugging messages, clears halts on
 * non-control endpoints, and translates the status to the corresponding
 * USB_STOR_XFER_xxx return code.
 */
static int interpret_urb_result(struct us_data *us, unsigned int pipe,
                                unsigned int length, int result, unsigned int actlen) {
    switch (result) {
    /* no error code; did we send all the data? */
    case 0:
        if (actlen != length) {
            return USB_STOR_XFER_SHORT;
        }
        return USB_STOR_XFER_GOOD;
    /* stalled */
    case -EPIPE:
        /* for control endpoints, (used by CB[I]) a stall indicates
        * a failed command */
        if (usb_pipecontrol(pipe)) {
            return USB_STOR_XFER_STALLED;
        }

        /* for other sorts of endpoint, clear the stall */
        if (usb_stor_clear_halt(us, pipe) < 0)
            return USB_STOR_XFER_ERROR;

        return USB_STOR_XFER_STALLED;

    /* babble - the device tried to send more than we wanted to read */
    case -EOVERFLOW:
        return USB_STOR_XFER_LONG;

    /* the transfer was cancelled by abort, disconnect, or timeout */
    case -ECONNRESET:
        return USB_STOR_XFER_ERROR;

    /* short scatter-gather read transfer */
    case -EREMOTEIO:
        return USB_STOR_XFER_SHORT;

    /* abort or disconnect in progress */
    case -EIO:
        return USB_STOR_XFER_ERROR;

    case -EINPROGRESS:
        return USB_STOR_XFER_ERROR;

    /* the catch-all error case */
    default:
        return USB_STOR_XFER_ERROR;
    }
}


/*
 * Transfer one buffer via bulk pipe, without timeouts, but allowing early
 * termination.  Return codes are USB_STOR_XFER_xxx.  If the bulk pipe
 * stalls during the transfer, the halt is automatically cleared.
 */
int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
                               void *buf, unsigned int length, unsigned int *act_len) {
    unsigned int act_xfer;
    int result, ret;
    HANDLE sc;
    us->current_urb->transfer_flags = 0;
    usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
                      usb_stor_blocking_completion, NULL);

    result = usb_stor_msg_common(us, us->current_urb, USB_STOR_BULK_TIMEOUT);

    sc = spin_lock_irq();
    act_xfer = us->current_urb->actual_length;
    if (act_len)
        *act_len = act_xfer;
    us->current_urb->actual_length = 0;
    spin_unlock_irq(sc);

    ret = interpret_urb_result(us, pipe, length, result, act_xfer);

    return ret;
}

static int usb_stor_bulk_srb(struct us_data* us,
                             u32 pipe, struct scsi_cmnd* srb) {
    int result, ret;
    unsigned int act_xfer;
    HANDLE sc;
    struct urb *urb = us->current_urb;
    u32 urb_flags = 0;

    if (!urb || srb->sdb.length < 0)
        return -EINVAL;

    if (usb_pipein(pipe))
        urb_flags |= URB_SHORT_NOT_OK;

    if (urb->transfer_flags & URB_NAK_LIMITED)
        urb_flags |= URB_NAK_LIMITED;

    urb->transfer_flags = urb_flags;
    usb_fill_bulk_urb(urb, us->pusb_dev, pipe,
                      srb->sdb.buf, srb->sdb.length,
                      usb_stor_blocking_completion, NULL);

    USB_ASSERT(srb->timeout != 0);
    result = usb_stor_msg_common(us, urb, srb->timeout);

    sc = spin_lock_irq();
    act_xfer = urb->actual_length;
    scsi_set_resid(srb, srb->sdb.length - act_xfer);
    srb->transfersize = act_xfer;
    urb->actual_length = 0;
    spin_unlock_irq(sc);

    ret = interpret_urb_result(us, pipe, srb->sdb.length, result, act_xfer);

    return ret;
}

/* To Report "Illegal Request: Invalid Field in CDB */
static unsigned char usb_stor_sense_invalidCDB[18] = {
    0x70, //[0]
    0x00,
    ILLEGAL_REQUEST, //[2]
    0x00, 0x00, 0x00, 0x00,
    0x0a, //[7]
    0x00, 0x00, 0x00, 0x00,
    0x24, //[12]
};

static unsigned char usb_stor_sense_none[18] = {
    0x70,             /* current error */
    0x00,
    SENSE_NONE,       /* not an error */
};


int usb_stor_bulk_transport(struct scsi_cmnd *srb, struct us_data *us) {
    struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
    struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
    unsigned int transfer_length = scsi_bufflen(srb);
    unsigned int residue;
    int result;
    int fake_sense = 0;
    unsigned int cswlen;
    unsigned int cbwlen = US_BULK_CB_WRAP_LEN;

    /* Take care of BULK32 devices; set extra byte to 0 */
    if (unlikely(us->fflags & US_FL_BULK32)) {
        cbwlen = 32;
        us->iobuf[31] = 0;
    }

    /* set up the command wrapper */
    bcb->Signature = US_BULK_CB_SIGN;
    bcb->DataTransferLength = transfer_length;
    bcb->Flags = srb->sc_data_direction == DIRECT_DATA_IN?
                 US_BULK_FLAG_IN : 0;
    bcb->Tag = ++us->tag;
    bcb->Lun = srb->device->lun;
    if (us->fflags & US_FL_SCM_MULT_TARG)
        bcb->Lun |= srb->device->id << 4;
    bcb->Length = (u8)srb->cmd_len;

    /* copy the command payload */
    HV_MEMSET(bcb->CDB, 0, sizeof(bcb->CDB));
    USB_MEMCPY(bcb->CDB, srb->cmnd, bcb->Length);

    result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, cbwlen, NULL);

    if (result != USB_STOR_XFER_GOOD) {
        return USB_STOR_TRANSPORT_ERROR;
    }

    USB_MSleep(7);

    /* DATA STAGE */
    if (unlikely(us->fflags & US_FL_GO_SLOW))
        USB_MSleep(100);

    if (transfer_length) {
        unsigned int pipe = srb->sc_data_direction == DIRECT_DATA_IN ?
                            us->recv_bulk_pipe : us->send_bulk_pipe;
        result = usb_stor_bulk_srb(us, pipe, srb);

        if (result == USB_STOR_XFER_ERROR) {
            return USB_STOR_TRANSPORT_ERROR;
        }

        if (result == USB_STOR_XFER_LONG) {
            fake_sense = 1;
        }

        if (result == USB_STOR_XFER_STALLED) {
            USB_LOGI("Stor data stalled.\n");
        }

        if (result == USB_STOR_XFER_SHORT &&
                srb->sc_data_direction == DIRECT_DATA_IN &&
                transfer_length - scsi_get_resid(srb) ==
                US_BULK_CS_WRAP_LEN) {

            /* For 8500, most times it's not an error.
             * but we lost the interrupt. */
            fake_sense = 2;
            goto skipped_data_phase;
        }
    }

    result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
                                        bcs, US_BULK_CS_WRAP_LEN, &cswlen);

 /* Some broken devices add unnecessary zero-length packets to the
     * end of their data transfers.  Such packets show up as 0-length
     * CSWs.  If we encounter such a thing, try to read the CSW again.
     */
    if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
        result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
                                            bcs, US_BULK_CS_WRAP_LEN, &cswlen);
    }

    /* did the attempt to read the CSW fail? */
    if (result == USB_STOR_XFER_STALLED) {
        /* get the status again */
        result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
                                            bcs, US_BULK_CS_WRAP_LEN, NULL);
    }

    if (result != USB_STOR_XFER_GOOD) {
        return USB_STOR_TRANSPORT_ERROR;
    }

skipped_data_phase:
    /* check bulk status */
    residue = bcs->Residue;

    if (!(bcs->Tag == us->tag || (us->fflags & US_FL_BULK_IGNORE_TAG))) {
        return USB_STOR_TRANSPORT_ERROR;
    }

    if (bcs->Status > US_BULK_STAT_PHASE) {
        return USB_STOR_TRANSPORT_ERROR;
    }

    /* Some broken devices report odd signatures, so we do not check them
     * for validity against the spec. We store the first one we see,
     * and check subsequent transfers for validity against this signature.
     */
    if (!us->bcs_signature) {
        us->bcs_signature = bcs->Signature;
        if (us->bcs_signature != US_BULK_CS_SIGN) {
        }
    } else if (bcs->Signature != us->bcs_signature) {
        return USB_STOR_TRANSPORT_ERROR;
    }

    /* try to compute the actual residue, based on how much data
     * was really transferred and what the device tells us */
    if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {

        /* Heuristically detect devices that generate bogus residues
         * by seeing what happens with INQUIRY and READ CAPACITY
         * commands.
         */
        if (bcs->Status == US_BULK_STAT_OK &&
                scsi_get_resid(srb) == 0 &&
                ((srb->cmnd[0] == INQUIRY &&
                  transfer_length == 36) ||
                 (srb->cmnd[0] == READ_CAPACITY &&
                  transfer_length == 8))) {
            us->fflags |= US_FL_IGNORE_RESIDUE;
        } else {
            residue = USB_MIN(residue, transfer_length);
            scsi_set_resid(srb, USB_MAX(scsi_get_resid(srb), (int) residue));
        }
    }
    /* based on the status code, we report good or bad */
    switch (bcs->Status) {
    case US_BULK_STAT_OK:
        /* device babbled -- return fake sense data */
        if (fake_sense == 1) {
            USB_MEMCPY(srb->sense_buffer,
                   usb_stor_sense_invalidCDB,
                   sizeof(usb_stor_sense_invalidCDB));
            return USB_STOR_TRANSPORT_NO_SENSE;
        } else if (fake_sense == 2) {
            USB_MEMCPY(srb->sense_buffer,
                   usb_stor_sense_none,
                   sizeof(usb_stor_sense_none));
            return USB_STOR_TRANSPORT_NO_SENSE;
        }
        /* command good -- note that data could be short */
        return USB_STOR_TRANSPORT_GOOD;

    case US_BULK_STAT_FAIL:
        /* command failed */
        return USB_STOR_TRANSPORT_FAILED;

    case US_BULK_STAT_PHASE:
        /* phase error -- note that a transport reset will be
         * invoked by the invoke_transport() function
         */
        return USB_STOR_TRANSPORT_ERROR;
    }

    /* we should never get here, but if we do, we're in trouble */
    return USB_STOR_TRANSPORT_ERROR;
}

/* This is the common part of the device reset code.
 *
 * It's handy that every transport mechanism uses the control endpoint for
 * resets.
 *
 * Basically, we send a reset with a 5-second timeout, so we don't get
 * jammed attempting to do the reset.
 */
static int usb_stor_reset_common(struct us_data *us,
                                 u8 request, u8 requesttype,
                                 u16 value, u16 index, void *data, u16 size) {
    int result;
    int result2;

    if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
        return -EIO;
    }

    result = usb_stor_control_msg(us, us->send_ctrl_pipe,
                                  request, requesttype, value,
                                  index, data, size, 5*0xf);
    if (result < 0) {
        return result;
    }

    result = usb_stor_clear_halt(us, us->recv_bulk_pipe);

    result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);

    /* return a result code based on the result of the clear-halts */
    if (result >= 0)
        result = result2;
    return USB_MIN(result, 0);
}

/* This issues a Bulk-only Reset to the device in question, including
 * clearing the subsequent endpoint halts that may occur.
 */
int usb_stor_bulk_reset(struct us_data *us) {
    return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
                                 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                                 0, us->ifnum, NULL, 0);
}

int usb_stor_port_reset(struct us_data *us) {
    int result = 0;
    /*for these devices we must use the class specific method */
    if (us->pusb_dev->quirks & USB_QUIRK_RESET)
        return -EPERM;

    result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
    if (result < 0) {
        USB_LOGE("unable to lock device for reset: %d.\n", result);
    } else {
        /* Were we disconnected while waiting for the lock? */
        if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
            result = -EIO;
            USB_LOGE("No reset during disconnect\n");
        } else {
            if (test_and_clear_bit(US_FLIDX_BUG_OVERFOUR, &us->dflags)) {
                us->pusb_dev->bus->hc_needreset = 1;
            }
            result = usb_reset_device(us->pusb_dev);
        }
        /* unlock? */
    }

    return result;
}

int usb_stor_bulk_max_lun(struct us_data *us) {
    int result;

    /* issue the command */
    us->iobuf[0] = 0;
    result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
                                  US_BULK_GET_MAX_LUN,
                                  USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                                  0, us->ifnum, us->iobuf, 1, USB_STOR_CTRL_TIMEOUT);

    if (result > 0) {
        if (us->iobuf[0] < 16) {
            return us->iobuf[0];
        } else {
            USB_LOGV("Max LUN %d is not valid, using 0 instead",us->iobuf[0]);
        }
    }

    return 0;
}

void usb_stor_stop_transport(struct us_data *us) {
    if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
        usb_unlink_urb(us->current_urb);
    }
}

static int do_auto_sense(struct us_data *us, struct scsi_cmnd *srb) {
    u8 retry = 0;
    int result = 0;
    int sense_size = US_SENSE_SIZE;
    struct scsi_cmnd sense_scmd;

    if (us->fflags & US_FL_SANE_SENSE) {
        sense_size = ~0;
    }
retry_sense:
    srb->sense_actual_length = 0;

    scsi_set_resid(&sense_scmd, 0);
    HV_MEMSET(srb->sense_buffer, 0, sense_size);
    sense_scmd.sdb.buf = srb->sense_buffer;
    sense_scmd.cmnd = srb->cmnd;
    us->scsi->ops->fill_request_sense(us->scsi, &sense_scmd, sense_size);
    if (us->subclass == USB_SC_RBC
            || us->subclass == USB_SC_SCSI
            || us->subclass == USB_SC_CYP_ATACB) {
        sense_scmd.cmd_len = 6;
    } else {
        sense_scmd.cmd_len = 12;
    }

    result = us->transport(&sense_scmd, us);

    if (result == USB_STOR_TRANSPORT_FAILED && retry++ < 3) {
        USB_MSleep(10);
        goto retry_sense;
    }
    srb->sense_actual_length = sense_scmd.transfersize;

    return result;
}

static int
try_do_sense(struct scsi_cmnd *srb, struct us_data *us, int result) {
    int retval = 0;
    int need_auto_sense = 0;

    if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) &&
            srb->sc_data_direction != DIRECT_DATA_IN) {
        need_auto_sense = 1;
    }

    if (result == USB_STOR_TRANSPORT_FAILED) {
        need_auto_sense = 1;
    }

    /*
     * Determine if this device is SAT by seeing if the
     * command executed successfully.  Otherwise we'll have
     * to wait for at least one CHECK_CONDITION to determine
     * SANE_SENSE support
     */
    if (unlikely((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) &&
                 result == USB_STOR_TRANSPORT_GOOD &&
                 !(us->fflags & US_FL_SANE_SENSE) &&
                 !(us->fflags & US_FL_BAD_SENSE) &&
                 !(srb->cmnd[2] & 0x20))) {
        us->fflags |= US_FL_SANE_SENSE;
    }

    /*
     * A short transfer on a command where we don't expect it
     * is unusual, but it doesn't mean we need to auto-sense.
     */
    if ((scsi_get_resid(srb) > 0) &&
            !((srb->cmnd[0] == REQUEST_SENSE) ||
              (srb->cmnd[0] == INQUIRY) ||
              (srb->cmnd[0] == MODE_SENSE) ||
              (srb->cmnd[0] == LOG_SENSE) ||
              (srb->cmnd[0] == MODE_SENSE_10))) {
    }

    /* Now, if we need to do the auto-sense, let's do it */
    if (need_auto_sense) {
        retval = do_auto_sense(us, srb);
        if (retval != USB_STOR_TRANSPORT_GOOD) {
            retval = us->transport_reset(us);
            if (!retval) {
                srb->result = DID_NEED_RETRY;
            }
            return retval;
        } else {
            srb->result = DID_CHECK_CONDITIONS;
        }
    } else {
        return 0;
    }

    /*
     * Some devices don't work or return incorrect data the first
     * time they get a READ(10) command, or for the first READ(10)
     * after a media change.  If the INITIAL_READ10 flag is set,
     * keep track of whether READ(10) commands succeed.  If the
     * previous one succeeded and this one failed, set the REDO_READ10
     * flag to force a retry.
     */
    if (unlikely((us->fflags & US_FL_INITIAL_READ10) &&
                 srb->cmnd[0] == READ_10)) {
        if (srb->result == DID_OK) {
            set_bit(US_FLIDX_READ10_WORKED, &us->dflags);
        } else if (test_bit(US_FLIDX_READ10_WORKED, &us->dflags)) {
            clear_bit(US_FLIDX_READ10_WORKED, &us->dflags);
            set_bit(US_FLIDX_REDO_READ10, &us->dflags);
        }

        /*
         * Next, if the REDO_READ10 flag is set, return a result
         * code that will cause the SCSI core to retry the READ(10)
         * command immediately.
         */
        if (test_bit(US_FLIDX_REDO_READ10, &us->dflags)) {
            clear_bit(US_FLIDX_REDO_READ10, &us->dflags);
            srb->result = DID_IMM_RETRY;
            srb->sense_buffer[0] = 0;
        }
    }

    /* Did we transfer less than the minimum amount required? */
    if ((srb->result == DID_OK || srb->sense_buffer[2] == 0) &&
            scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) {
        srb->result = DID_ERROR;
    }

    return 0;
}

static int repair_storage_device(struct us_data *us) {
    int result;
    /* Set the RESETTING bit, and clear the ABORTING bit so that
     * the reset may proceed. */
    HANDLE sc = spin_lock_irq();
    set_bit(US_FLIDX_RESETTING, &us->dflags);
    clear_bit(US_FLIDX_ABORTING, &us->dflags);
    spin_unlock_irq(sc);

    result = usb_stor_port_reset(us);
    if (result == -ENODEV) {
        goto finish;
    }

    if (result < 0) {
        result = us->transport_reset(us);
    }

finish:
    if (result == -ENODEV) {
        us->srb->result = DID_NOT_CONNECT;
    }

    clear_bit(US_FLIDX_RESETTING, &us->dflags);
    return result;
}

void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) {
    int result;
    /* send the command to the transport layer */
    scsi_set_resid(srb, 0);
    result = us->transport(srb, us);


    if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
        srb->result = DID_ABORT;
        goto Handle_Errors;
    }
    /* if there is a transport error, reset and don't auto-sense */
    if (result == USB_STOR_TRANSPORT_ERROR) {
        srb->result = DID_ERROR;
        goto Handle_Errors;
    }

    /* if the transport provided its own sense data, don't auto-sense */
    if (result == USB_STOR_TRANSPORT_NO_SENSE) {
        srb->result = DID_CHECK_CONDITIONS;
        return;
    }

    srb->result = DID_OK;
    result = try_do_sense(srb, us, result);
    if (!result) {
        return;
    }

    srb->result = DID_ERROR;
Handle_Errors:
    if (!usb_device_exist(us->pusb_dev)) {
        srb->result = DID_NOT_CONNECT;
        return;
    }

    result = repair_storage_device(us);
    if (result == 0) {
        srb->result = DID_NEED_RETRY;
    }
}
