Exemple #1
0
/*
 *  This issues a Bulk-only Reset to the device in question, including
 *  clearing the subsequent endpoint halts that may occur.
 */
int  UMAS_BulkReset(UMAS_DATA_T *umas)
{
    int result;

    UMAS_VDEBUG("Bulk reset requested\n");
    printf("UMAS_BulkReset!\n");

    /* if the device was removed, then we're already reset */
    if(!umas->pusb_dev)
        return SUCCESS;

    result = USBH_SendCtrlMsg(umas->pusb_dev,
                              usb_sndctrlpipe(umas->pusb_dev, 0), UMAS_BULK_RESET_REQUEST,
                              USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, umas->ifnum,
                              NULL, 0, 0);
    if(result < 0)
    {
        UMAS_DEBUG("Bulk soft reset failed %d\n", result);
        return FAILED;
    }

    clear_halt(umas->pusb_dev, usb_rcvbulkpipe(umas->pusb_dev, umas->ep_in));
    clear_halt(umas->pusb_dev, usb_sndbulkpipe(umas->pusb_dev, umas->ep_out));

    UMAS_VDEBUG("Bulk soft reset completed\n");
    return SUCCESS;
}
Exemple #2
0
/*
 *  This issues a CB[I] Reset to the device in question
 */
int  UMAS_CbReset(UMAS_DATA_T *umas)
{
    uint8_t   cmd[12];
    int     result;

    /* if the device was removed, then we're already reset */
    if(!umas->pusb_dev)
        return SUCCESS;

    memset(cmd, 0xFF, sizeof(cmd));
    cmd[0] = SEND_DIAGNOSTIC;
    cmd[1] = 4;
    result = USBH_SendCtrlMsg(umas->pusb_dev, usb_sndctrlpipe(umas->pusb_dev, 0),
                              US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                              0, umas->ifnum, cmd, sizeof(cmd), 0);
    if(result < 0)
    {
        UMAS_DEBUG("UMAS_CbReset - CB[I] soft reset failed %d\n", result);
        return FAILED;
    }

    UMAS_VDEBUG("UMAS_CbReset - clearing endpoint halt\n");
    clear_halt(umas->pusb_dev, usb_rcvbulkpipe(umas->pusb_dev, umas->ep_in));
    clear_halt(umas->pusb_dev, usb_rcvbulkpipe(umas->pusb_dev, umas->ep_out));

    UMAS_VDEBUG("UMAS_CbReset - done\n");
    /* return a result code based on the result of the control message */
    return SUCCESS;
}
Exemple #3
0
/* Determine what the maximum LUN supported is */
int  UMAS_BulkMaxLun(UMAS_DATA_T *umas)
{
    uint8_t     data;
    int     result;
    int     pipe;
    uint8_t     dma_buff[4];

    /* issue the command */
    pipe = usb_rcvctrlpipe(umas->pusb_dev, 0);
    result = USBH_SendCtrlMsg(umas->pusb_dev, pipe, UMAS_BULK_GET_MAX_LUN,
                              USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                              0, umas->ifnum, dma_buff, 1, 0);

    data = dma_buff[0];

    UMAS_DEBUG("GetMaxLUN command result is %d, data is %d\n", result, data);

    /* if we have a successful request, return the result */
    if(result == 1)
        return data;

    /* if we get a STALL, clear the stall */
    if(result == USB_ERR_PIPE)
    {
        UMAS_DEBUG("clearing endpoint halt for pipe 0x%x\n", pipe);
        clear_halt(umas->pusb_dev, pipe);
    }

    /* return the default -- no LUNs */
    return 0;
}
Exemple #4
0
/*
 *  Transfer one SCSI scatter-gather buffer via bulk transfer
 *
 *  Note that this function is necessary because we want the ability to
 *  use scatter-gather memory.  Good performance is achieved by a combination
 *  of scatter-gather and clustering (which makes each chunk bigger).
 *
 *  Note that the lower layer will always retry when a NAK occurs, up to the
 *  timeout limit.  Thus we don't have to worry about it for individual
 *  packets.
 */
static int  usb_stor_transfer_partial(UMAS_DATA_T *umas, char *buf, int length)
{
    int     result;
    uint32_t  partial;
    int     pipe;

    /* calculate the appropriate pipe information */
    if(umas->srb.sc_data_direction == SCSI_DATA_READ)
        pipe = usb_rcvbulkpipe(umas->pusb_dev, umas->ep_in);
    else
        pipe = usb_sndbulkpipe(umas->pusb_dev, umas->ep_out);

    /* transfer the data */
    UMAS_VDEBUG("usb_stor_transfer_partial - xfer %d bytes\n", length);
    result = usb_stor_bulk_msg(umas, buf, pipe, length, &partial);
    UMAS_VDEBUG("usb_stor_bulk_msg() returned %d xferred %d/%d\n", result, partial, length);
    //UMAS_DEBUG("usb_stor_bulk_msg() returned %d xferred %d/%d\n", result, partial, length);

    /* if we stall, we need to clear it before we go on */
    if(result == USB_ERR_PIPE)
    {
        UMAS_DEBUG("usb_stor_transfer_partial - clearing endpoint halt for pipe 0x%x\n", pipe);
        clear_halt(umas->pusb_dev, pipe);
    }

    /* did we send all the data? */
    if(partial == length)
    {
        UMAS_VDEBUG("usb_stor_transfer_partial - transfer complete\n");
        return UMAS_BULK_TRANSFER_GOOD;
    }

    /* uh oh... we have an error code, so something went wrong. */
    if(result)
    {
        /* NAK - that means we've retried a few times already */
        if(result == USB_ERR_TIMEOUT)
        {
            UMAS_DEBUG("usb_stor_transfer_partial - device NAKed\n");
            return UMAS_BULK_TRANSFER_FAILED;
        }

        /* USB_ERR_NOENT -- we canceled this transfer */
        if(result == USB_ERR_NOENT)
        {
            UMAS_DEBUG("usb_stor_transfer_partial - transfer aborted\n");
            return UMAS_BULK_TRANSFER_ABORTED;
        }

        /* the catch-all case */
        UMAS_DEBUG("usb_stor_transfer_partial - unknown error\n");
        return UMAS_BULK_TRANSFER_FAILED;
    }

    /* no error code, so we must have transferred some data, just not all of it */
    return UMAS_BULK_TRANSFER_SHORT;
}
Exemple #5
0
/*
 * Control/Bulk transport
 */
int  UMAS_CbTransport(SCSI_CMD_T *srb, UMAS_DATA_T *umas)
{
    int    result;

    /* COMMAND STAGE */
    /* let's send the command via the control pipe */
    result = usb_stor_control_msg(umas, usb_sndctrlpipe(umas->pusb_dev, 0),
                                  US_CBI_ADSC,
                                  USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
                                  umas->ifnum, srb->cmnd, srb->cmd_len);

    /* check the return code for the command */
    UMAS_VDEBUG("UMAS_CbTransport - Call to usb_stor_control_msg() returned %d\n", result);
    if(result < 0)
    {
        /* if the command was aborted, indicate that */
        if(result == USB_ERR_NOENT)
            return USB_STOR_TRANSPORT_ABORTED;

        /* a stall is a fatal condition from the device */
        if(result == USB_ERR_PIPE)
        {
            UMAS_DEBUG("UMAS_CbTransport - Stall on control pipe. Clearing\n");
            result = clear_halt(umas->pusb_dev, usb_sndctrlpipe(umas->pusb_dev, 0));
            UMAS_DEBUG("UMAS_CbTransport - clear_halt() returns %d\n", result);
            return USB_STOR_TRANSPORT_FAILED;
        }

        /* Uh oh... serious problem here */
        return USB_STOR_TRANSPORT_ERROR;
    }

    /* DATA STAGE */
    /* transfer the data payload for this command, if one exists */
    if(usb_stor_transfer_length(srb))
    {
        us_transfer(srb, umas);
        UMAS_VDEBUG("UMAS_CbTransport - CB data stage result is 0x%x\n", srb->result);

        /* if it was aborted, we need to indicate that */
        if(srb->result == USB_STOR_TRANSPORT_ABORTED)
            return USB_STOR_TRANSPORT_ABORTED;
    }

    /* STATUS STAGE */
    /* NOTE: CB does not have a status stage.  Silly, I know.  So
     * we have to catch this at a higher level.
     */
    return USB_STOR_TRANSPORT_GOOD;
}
Exemple #6
0
int  UMAS_CbiTransport(SCSI_CMD_T *srb, UMAS_DATA_T *umas)
{
    int result;

    /* Set up for status notification */
    umas->ip_wanted = 1;

    /* re-initialize the mutex so that we avoid any races with
     * early/late IRQs from previous commands */

    /* COMMAND STAGE */
    /* let's send the command via the control pipe */
    result = usb_stor_control_msg(umas, usb_sndctrlpipe(umas->pusb_dev, 0),
                                  US_CBI_ADSC,
                                  USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
                                  umas->ifnum, srb->cmnd, srb->cmd_len);

    /* check the return code for the command */
    UMAS_VDEBUG("Call to usb_stor_control_msg() returned %d\n", result);
    if(result < 0)
    {
        /* if the command was aborted, indicate that */
        if(result == USB_ERR_NOENT)
            return USB_STOR_TRANSPORT_ABORTED;

        /* STALL must be cleared when they are detected */
        if(result == USB_ERR_PIPE)
        {
            UMAS_VDEBUG("-- Stall on control pipe. Clearing\n");
            result = clear_halt(umas->pusb_dev,  usb_sndctrlpipe(umas->pusb_dev, 0));
            UMAS_VDEBUG("-- clear_halt() returns %d\n", result);
            return USB_STOR_TRANSPORT_FAILED;
        }

        /* Uh oh... serious problem here */
        return USB_STOR_TRANSPORT_ERROR;
    }

    /* DATA STAGE */
    /* transfer the data payload for this command, if one exists*/
    if(usb_stor_transfer_length(srb))
    {
        us_transfer(srb, umas);
        UMAS_VDEBUG("CBI data stage result is 0x%x\n", srb->result);

        /* if it was aborted, we need to indicate that */
        if(srb->result == USB_STOR_TRANSPORT_ABORTED)
            return USB_STOR_TRANSPORT_ABORTED;

    }

    /* STATUS STAGE */

    //UMAS_VDEBUG("Current value of ip_waitq is: %d\n", umas->ip_waitq.count);

    /* if we were woken up by an abort instead of the actual interrupt */
    if(umas->ip_wanted)
    {
        UMAS_DEBUG("Did not get interrupt on CBI\n");
        umas->ip_wanted = 0;
        return USB_STOR_TRANSPORT_ABORTED;
    }

    UMAS_VDEBUG("Got interrupt data (0x%x, 0x%x)\n",  umas->irqdata[0], umas->irqdata[1]);

    /*
     *  UFI gives umas ASC and ASCQ, like a request sense
     *
     *  REQUEST_SENSE and INQUIRY don't affect the sense data on UFI
     *  devices, so we ignore the information for those commands.  Note
     *  that this means we could be ignoring a real error on these
     *  commands, but that can't be helped.
     */
    if(umas->subclass == UMAS_SC_UFI)
    {
        if((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY))
            return USB_STOR_TRANSPORT_GOOD;
        else
        {
            if(((uint8_t*)umas->irq_urb->transfer_buffer)[0])
                return USB_STOR_TRANSPORT_FAILED;
            else
                return USB_STOR_TRANSPORT_GOOD;
        }
    }

    /*
     *  If not UFI, we interpret the data as a result code
     *  The first byte should always be a 0x0
     *  The second byte & 0x0F should be 0x0 for good, otherwise error
     */
    if(umas->irqdata[0])
    {
        UMAS_VDEBUG("CBI IRQ data showed reserved bType %d\n", umas->irqdata[0]);
        return USB_STOR_TRANSPORT_ERROR;
    }

    switch(umas->irqdata[1] & 0x0F)
    {
        case 0x00:
            return USB_STOR_TRANSPORT_GOOD;
        case 0x01:
            return USB_STOR_TRANSPORT_FAILED;
        default:
            return USB_STOR_TRANSPORT_ERROR;
    }
}
Exemple #7
0
int  UMAS_BulkTransport(SCSI_CMD_T *srb, UMAS_DATA_T *umas)
{
    int     result, status = 0;
    int     pipe;
    uint32_t    partial;
    struct bulk_cb_wrap  bcb;
    struct bulk_cs_wrap  bcs;

    /* if the device was removed, then we're already reset */
    if(!umas->pusb_dev)
        return SUCCESS;

    /* set up the command wrapper */
    bcb.Signature = UMAS_BULK_CB_SIGN;
    bcb.DataTransferLength = usb_stor_transfer_length(srb);
    bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
    bcb.Tag = srb->serial_number;
    bcb.Lun = srb->cmnd[1] >> 5;

    if(umas->flags & UMAS_FL_SCM_MULT_TARG)
        bcb.Lun |= srb->target << 4;
    bcb.Length = srb->cmd_len;

    /* construct the pipe handle */
    pipe = usb_sndbulkpipe(umas->pusb_dev, umas->ep_out);

    /* copy the command payload */
    memset(bcb.CDB, 0, sizeof(bcb.CDB));
    memcpy(bcb.CDB, srb->cmnd, bcb.Length);

    /* send it to out endpoint */
    UMAS_VDEBUG("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
                bcb.Signature, bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0x0F),
                bcb.DataTransferLength, bcb.Flags, bcb.Length);
    result = usb_stor_bulk_msg(umas, &bcb, pipe, UMAS_BULK_CB_WRAP_LEN, &partial);
    UMAS_VDEBUG("Bulk command transfer result=%d\n", result);

    /* if the command was aborted, indicate that */
    if(result == USB_ERR_NOENT)
        return USB_STOR_TRANSPORT_ABORTED;

    /* if we stall, we need to clear it before we go on */
    if(result == USB_ERR_PIPE)
    {
        UMAS_DEBUG("UMAS_BulkTransport - 1 clearing endpoint halt for pipe 0x%x\n", pipe);
        clear_halt(umas->pusb_dev, pipe);
    }
    else if(result)
    {
        /* unknown error -- we've got a problem */
        status = USB_STOR_TRANSPORT_ERROR;
        goto bulk_error;
    }

    /* if the command transferred well, then we go to the data stage */
    if(result == 0)
    {
        /* send/receive data payload, if there is any */
        if(bcb.DataTransferLength)
        {
            us_transfer(srb, umas);

            /* if it was aborted, we need to indicate that */
            if(srb->result == USB_STOR_TRANSPORT_ABORTED)
            {
                status = USB_STOR_TRANSPORT_ABORTED;
                goto bulk_error;
            }
        }
    }

    /*
     *  See flow chart on pg 15 of the Bulk Only Transport spec for
     *  an explanation of how this code works.
     */

    /* construct the pipe handle */
    pipe = usb_rcvbulkpipe(umas->pusb_dev, umas->ep_in);

    /* get CSW for device status */
    UMAS_VDEBUG("Attempting to get CSW...\n");
    result = usb_stor_bulk_msg(umas, (char *)&bcs, pipe, UMAS_BULK_CS_WRAP_LEN, &partial);

    /* if the command was aborted, indicate that */
    if(result == USB_ERR_NOENT)
    {
        status = USB_STOR_TRANSPORT_ABORTED;
        goto bulk_error;
    }

    /* did the attempt to read the CSW fail? */
    if(result == USB_ERR_PIPE)
    {
        UMAS_DEBUG("get CSW failed - clearing endpoint halt for pipe 0x%x\n", pipe);
        clear_halt(umas->pusb_dev, pipe);

        /* get the status again */
        UMAS_DEBUG("Attempting to get CSW (2nd try)...\n");
        result = usb_stor_bulk_msg(umas, &bcs, pipe, UMAS_BULK_CS_WRAP_LEN, &partial);

        /* if the command was aborted, indicate that */
        if(result == USB_ERR_NOENT)
        {
            UMAS_DEBUG("get CSW Command was aborted!\n");
            status = USB_STOR_TRANSPORT_ABORTED;
            goto bulk_error;
        }

        /* if it fails again, we need a reset and return an error*/
        if(result == USB_ERR_PIPE)
        {
            UMAS_DEBUG("get CSW command 2nd try failed - clearing halt for pipe 0x%x\n", pipe);
            clear_halt(umas->pusb_dev, pipe);
            status = USB_STOR_TRANSPORT_ERROR;
            goto bulk_error;
        }
    }

    /* if we still have a failure at this point, we're in trouble */
    UMAS_VDEBUG("Bulk status result = %d\n", result);
    if(result)
    {
        status = USB_STOR_TRANSPORT_ERROR;
        goto bulk_error;
    }

    /* check bulk status */
    UMAS_VDEBUG("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
                USB_SWAP32(bcs.Signature), bcs.Tag, bcs.Residue, bcs.Status);
    if((bcs.Signature != UMAS_BULK_CS_SIGN) || (bcs.Tag != bcb.Tag) ||
            (bcs.Status > UMAS_BULK_STAT_PHASE) || (partial != 13))
    {
        UMAS_DEBUG("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
                   USB_SWAP32(bcs.Signature), bcs.Tag, bcs.Residue, bcs.Status);
        status = USB_STOR_TRANSPORT_ERROR;
        goto bulk_error;
    }

    /* based on the status code, we report good or bad */
    switch(bcs.Status)
    {
        case UMAS_BULK_STAT_OK:
            /* command good -- note that data could be short */
            return USB_STOR_TRANSPORT_GOOD;

        case UMAS_BULK_STAT_FAIL:
            /* command failed */
            status = USB_STOR_TRANSPORT_FAILED;
            goto bulk_error;

        case UMAS_BULK_STAT_PHASE:
            /* phase error -- note that a transport reset will be
             * invoked by the invoke_transport() function
             */
            status = USB_STOR_TRANSPORT_ERROR;
            goto bulk_error;
    }
    /* we should never get here, but if we do, we're in trouble */

bulk_error:
    return status;
}
static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
{
    struct usbdevfs_urb *urb;
    AsyncURB *aurb;
    int ret;

    aurb = async_alloc();
    if (!aurb) {
        dprintf("husb: async malloc failed\n");
        return USB_RET_NAK;
    }
    aurb->hdev   = s;
    aurb->packet = p;

    urb = &aurb->urb;

    if (p->pid == USB_TOKEN_IN)
    	urb->endpoint = p->devep | 0x80;
    else
    	urb->endpoint = p->devep;

    if (is_halted(s, p->devep)) {
	ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
        if (ret < 0) {
            dprintf("husb: failed to clear halt. ep 0x%x errno %d\n", 
                   urb->endpoint, errno);
            return USB_RET_NAK;
        }
        clear_halt(s, p->devep);
    }

    urb->buffer        = p->data;
    urb->buffer_length = p->len;

    if (is_isoc(s, p->devep)) {
        /* Setup ISOC transfer */
        urb->type     = USBDEVFS_URB_TYPE_ISO;
        urb->flags    = USBDEVFS_URB_ISO_ASAP;
        urb->number_of_packets = 1;
        urb->iso_frame_desc[0].length = p->len;
    } else {
        /* Setup bulk transfer */
        urb->type     = USBDEVFS_URB_TYPE_BULK;
    }

    urb->usercontext = s;

    ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);

    dprintf("husb: data submit. ep 0x%x len %u aurb %p\n", urb->endpoint, p->len, aurb);

    if (ret < 0) {
        dprintf("husb: submit failed. errno %d\n", errno);
        async_free(aurb);

        switch(errno) {
        case ETIMEDOUT:
            return USB_RET_NAK;
        case EPIPE:
        default:
            return USB_RET_STALL;
        }
    }

    usb_defer_packet(p, async_cancel, aurb);
    return USB_RET_ASYNC;
}