Esempio n. 1
0
/*
 * Transfer an entire SCSI command's worth of data payload over the bulk
 * pipe.
 *
 * Note that this uses usb_stor_transfer_partial to achieve its goals -- this
 * function simply determines if we're going to use scatter-gather or not,
 * and acts appropriately.  For now, it also re-interprets the error codes.
 */
void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us)
{
	int i;
	int result = -1;
	struct scatterlist *sg;
	unsigned int total_transferred = 0;
	unsigned int transfer_amount;



	/* calculate how much we want to transfer */
	transfer_amount = usb_stor_transfer_length(srb);




	/* was someone foolish enough to request more data than available
	 * buffer space? */
	if (transfer_amount > srb->request_bufflen)
		transfer_amount = srb->request_bufflen;

	/* are we scatter-gathering? */
	if (srb->use_sg) {

		/* loop over all the scatter gather structures and 
		 * make the appropriate requests for each, until done
		 */
		sg = (struct scatterlist *) srb->request_buffer;
		for (i = 0; i < srb->use_sg; i++) {






			if (transfer_amount - total_transferred >= 
					sg[i].length) {
				result = usb_stor_transfer_partial(us,
						sg[i].address, sg[i].length);
				total_transferred += sg[i].length;
			} else
				result = usb_stor_transfer_partial(us,
						sg[i].address,
						transfer_amount - total_transferred);

			/* if we get an error, end the loop here */
			if (result)
				break;
		}

	}
	else
		/* no scatter-gather, just make the request */
		result = usb_stor_transfer_partial(us, srb->request_buffer, 
					     transfer_amount);

	/* return the result in the data structure itself */
	srb->result = result;
}
Esempio n. 2
0
/*
 * Control/Bulk transport
 */
int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
{
	int result;

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

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

		/* a stall is a fatal condition from the device */
		if (result == -EPIPE) {
			US_DEBUGP("-- Stall on control pipe. Clearing\n");
			result = usb_stor_clear_halt(us,
				usb_sndctrlpipe(us->pusb_dev, 0));

			/* if the command was aborted, indicate that */
			if (result == -ECONNRESET)
				return USB_STOR_TRANSPORT_ABORTED;
			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)) {
		usb_stor_transfer(srb, us);
		result = srb->result;
		US_DEBUGP("CB data stage result is 0x%x\n", result);

		/* report any errors */
		if (result == US_BULK_TRANSFER_ABORTED) {
			return USB_STOR_TRANSPORT_ABORTED;
		}
		if (result == US_BULK_TRANSFER_FAILED) {
			return USB_STOR_TRANSPORT_FAILED;
		}
	}

	/* 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;
}
Esempio n. 3
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;
}
Esempio n. 4
0
/*
 *  Transfer an entire SCSI command's worth of data payload over the bulk pipe.
 *
 *  Note that this uses usb_stor_transfer_partial to achieve it's goals -- this
 *  function simply determines if we're going to use scatter-gather or not,
 *  and acts appropriately.  For now, it also re-interprets the error codes.
 */
static void  us_transfer(SCSI_CMD_T *srb, UMAS_DATA_T* umas)
{
    int     i;
    int     result = -1;
    uint32_t  total_transferred = 0;
    uint32_t  transfer_amount;
    SCATTER_LIST_T  *sg;

    /* calculate how much we want to transfer */
    transfer_amount = usb_stor_transfer_length(srb);

    /* Was someone foolish enough to request more data than available buffer space?  */
    if(transfer_amount > srb->request_bufflen)
        transfer_amount = srb->request_bufflen;

    /* are we scatter-gathering? */
    if(srb->use_sg)
    {
        /*
         * loop over all the scatter gather structures and
         * make the appropriate requests for each, until done
         */
        sg = (SCATTER_LIST_T *) srb->request_buff;
        for(i = 0; i < srb->use_sg; i++)
        {
            /* transfer the lesser of the next buffer or the remaining data */
            if(transfer_amount - total_transferred >= sg[i].length)
            {
                result = usb_stor_transfer_partial(umas, sg[i].address, sg[i].length);
                total_transferred += sg[i].length;
            }
            else
                result = usb_stor_transfer_partial(umas, sg[i].address,
                                                   transfer_amount - total_transferred);
            /* if we get an error, end the loop here */
            if(result)
                break;
        }
    }
    else  /* no scatter-gather, just make the request */
        result = usb_stor_transfer_partial(umas, (char *)srb->request_buff, transfer_amount);

    /* return the result in the data structure itself */
    srb->result = result;
}
Esempio n. 5
0
int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
{
	int result;

	/* Set up for status notification */
	atomic_set(us->ip_wanted, 1);

	/* re-initialize the mutex so that we avoid any races with
	 * early/late IRQs from previous commands */
	init_MUTEX_LOCKED(&(us->ip_waitq));

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

	/* check the return code for the command */
	US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
	if (result < 0) {
		/* Reset flag for status notification */
		atomic_set(us->ip_wanted, 0);
	}

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

	/* STALL must be cleared when it is detected */
	if (result == -EPIPE) {
		US_DEBUGP("-- Stall on control pipe. Clearing\n");
		result = usb_stor_clear_halt(us,	
			usb_sndctrlpipe(us->pusb_dev, 0));

		/* if the command was aborted, indicate that */
		if (result == -ECONNRESET)
			return USB_STOR_TRANSPORT_ABORTED;
		return USB_STOR_TRANSPORT_FAILED;
	}

	if (result < 0) {
		/* 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)) {
		usb_stor_transfer(srb, us);
		result = srb->result;
		US_DEBUGP("CBI data stage result is 0x%x\n", result);

		/* report any errors */
		if (result == US_BULK_TRANSFER_ABORTED) {
			atomic_set(us->ip_wanted, 0);
			return USB_STOR_TRANSPORT_ABORTED;
		}
		if (result == US_BULK_TRANSFER_FAILED) {
			atomic_set(us->ip_wanted, 0);
			return USB_STOR_TRANSPORT_FAILED;
		}
	}

	/* STATUS STAGE */

	/* go to sleep until we get this interrupt */
	US_DEBUGP("Current value of ip_waitq is: %d\n", atomic_read(&us->ip_waitq.count));
	down(&(us->ip_waitq));

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

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

	/* UFI gives us 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 (us->subclass == US_SC_UFI) {
		if (srb->cmnd[0] == REQUEST_SENSE ||
		    srb->cmnd[0] == INQUIRY)
			return USB_STOR_TRANSPORT_GOOD;
		else
			if (((unsigned char*)us->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 (us->irqdata[0]) {
		US_DEBUGP("CBI IRQ data showed reserved bType %d\n",
				us->irqdata[0]);
		return USB_STOR_TRANSPORT_ERROR;
	}

	switch (us->irqdata[1] & 0x0F) {
		case 0x00: 
			return USB_STOR_TRANSPORT_GOOD;
		case 0x01: 
			return USB_STOR_TRANSPORT_FAILED;
		default: 
			return USB_STOR_TRANSPORT_ERROR;
	}

	/* we should never get here, but if we do, we're in trouble */
	return USB_STOR_TRANSPORT_ERROR;
}
Esempio n. 6
0
int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
{
	struct bulk_cb_wrap *bcb;
	struct bulk_cs_wrap *bcs;
	int result;
	int pipe;
	int partial;
	int ret = USB_STOR_TRANSPORT_ERROR;

	bcb = kmalloc(sizeof *bcb, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
	if (!bcb) {
		return USB_STOR_TRANSPORT_ERROR;
	}
	bcs = kmalloc(sizeof *bcs, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
	if (!bcs) {
		kfree(bcb);
		return USB_STOR_TRANSPORT_ERROR;
	}

	/* set up the command wrapper */
	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
	bcb->DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb));
	bcb->Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
	bcb->Tag = ++(us->tag);
	bcb->Lun = srb->cmnd[1] >> 5;
	if (us->flags & US_FL_SCM_MULT_TARG)
		bcb->Lun |= srb->target << 4;
	bcb->Length = srb->cmd_len;

	/* construct the pipe handle */
	pipe = usb_sndbulkpipe(us->pusb_dev, us->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 */
	US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
		  le32_to_cpu(bcb->Signature), bcb->Tag,
		  (bcb->Lun >> 4), (bcb->Lun & 0x0F), 
		  bcb->DataTransferLength, bcb->Flags, bcb->Length);
	result = usb_stor_bulk_msg(us, bcb, pipe, US_BULK_CB_WRAP_LEN, 
				   &partial);
	US_DEBUGP("Bulk command transfer result=%d\n", result);

	/* if the command was aborted, indicate that */
	if (result == -ECONNRESET) {
		ret = USB_STOR_TRANSPORT_ABORTED;
		goto out;
	}

	/* if we stall, we need to clear it before we go on */
	if (result == -EPIPE) {
		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
		result = usb_stor_clear_halt(us, pipe);

		/* if the command was aborted, indicate that */
		if (result == -ECONNRESET) {
			ret = USB_STOR_TRANSPORT_ABORTED;
			goto out;
		}
		result = -EPIPE;
	} else if (result) {
		/* unknown error -- we've got a problem */
		ret = USB_STOR_TRANSPORT_ERROR;
		goto out;
	}

	/* if the command transfered well, then we go to the data stage */
	if (result == 0) {
		/* send/receive data payload, if there is any */
		if (bcb->DataTransferLength) {
			usb_stor_transfer(srb, us);
			result = srb->result;
			US_DEBUGP("Bulk data transfer result 0x%x\n", result);

			/* if it was aborted, we need to indicate that */
			if (result == US_BULK_TRANSFER_ABORTED) {
				ret = USB_STOR_TRANSPORT_ABORTED;
				goto out;
			}
		}
	}

	/* 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(us->pusb_dev, us->ep_in);

	/* get CSW for device status */
	US_DEBUGP("Attempting to get CSW...\n");
	result = usb_stor_bulk_msg(us, bcs, pipe, US_BULK_CS_WRAP_LEN, 
				   &partial);

	/* if the command was aborted, indicate that */
	if (result == -ECONNRESET) {
		ret = USB_STOR_TRANSPORT_ABORTED;
		goto out;
	}

	/* did the attempt to read the CSW fail? */
	if (result == -EPIPE) {
		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
		result = usb_stor_clear_halt(us, pipe);

		/* if the command was aborted, indicate that */
		if (result == -ECONNRESET) {
			ret = USB_STOR_TRANSPORT_ABORTED;
			goto out;
		}

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

		/* if the command was aborted, indicate that */
		if (result == -ECONNRESET) {
			ret = USB_STOR_TRANSPORT_ABORTED;
			goto out;
		}

		/* if it fails again, we need a reset and return an error*/
		if (result == -EPIPE) {
			US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
			result = usb_stor_clear_halt(us, pipe);

			/* if the command was aborted, indicate that */
			if (result == -ECONNRESET) {
				ret = USB_STOR_TRANSPORT_ABORTED;
			} else {
				ret = USB_STOR_TRANSPORT_ERROR;
			}
			goto out;
		}
	}

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

	/* check bulk status */
	US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
		  le32_to_cpu(bcs->Signature), bcs->Tag, 
		  bcs->Residue, bcs->Status);
	if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) || 
	    bcs->Tag != bcb->Tag || 
	    bcs->Status > US_BULK_STAT_PHASE || partial != 13) {
		US_DEBUGP("Bulk logical error\n");
		ret = USB_STOR_TRANSPORT_ERROR;
		goto out;
	}

	/* based on the status code, we report good or bad */
	switch (bcs->Status) {
		case US_BULK_STAT_OK:
			/* command good -- note that data could be short */
			ret = USB_STOR_TRANSPORT_GOOD;
			goto out;

		case US_BULK_STAT_FAIL:
			/* command failed */
			ret = USB_STOR_TRANSPORT_FAILED;
			goto out;

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

	/* we should never get here, but if we do, we're in trouble */

 out:
	kfree(bcb);
	kfree(bcs);
	return ret;
}
Esempio n. 7
0
/*
 * Transport for the Freecom USB/IDE adaptor.
 *
 */
int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
{
        struct freecom_cb_wrap *fcb;
        struct freecom_status  *fst;
        int ipipe, opipe;             /* We need both pipes. */
        int result;
        int partial;
        int length;
        freecom_udata_t extra;

        extra = (freecom_udata_t) us->extra;

        fcb = (struct freecom_cb_wrap *) extra->buffer;
        fst = (struct freecom_status *) extra->buffer;

        US_DEBUGP("Freecom TRANSPORT STARTED\n");

        /* Get handles for both transports. */
        opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);
        ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in);

#if 0
        /* Yuck, let's see if this helps us.  Artificially increase the
         * length on this. */
        if (srb->cmnd[0] == 0x03 && srb->cmnd[4] == 0x12)
                srb->cmnd[4] = 0x0E;
#endif

        /* The ATAPI Command always goes out first. */
        fcb->Type = FCM_PACKET_ATAPI | 0x00;
        fcb->Timeout = 0;
        memcpy (fcb->Atapi, srb->cmnd, 12);
        memset (fcb->Filler, 0, sizeof (fcb->Filler));

        US_DEBUG(pdump (srb->cmnd, 12));

        /* Send it out. */
        result = usb_stor_bulk_msg (us, fcb, opipe,
                        FCM_PACKET_LENGTH, &partial);

        /* The Freecom device will only fail if there is something wrong in
         * USB land.  It returns the status in its own registers, which
         * come back in the bulk pipe. */
        if (result != 0) {
                US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
                                result, partial);

		/* -ENOENT -- we canceled this transfer */
		if (result == -ENOENT) {
			US_DEBUGP("freecom_transport(): transfer aborted\n");
			return US_BULK_TRANSFER_ABORTED;
		}

                return USB_STOR_TRANSPORT_ERROR;
        }

        /* There are times we can optimize out this status read, but it
         * doesn't hurt us to always do it now. */
        result = usb_stor_bulk_msg (us, fst, ipipe,
                        FCM_PACKET_LENGTH, &partial);
        US_DEBUGP("foo Status result %d %d\n", result, partial);
	/* -ENOENT -- we canceled this transfer */
	if (result == -ENOENT) {
		US_DEBUGP("freecom_transport(): transfer aborted\n");
		return US_BULK_TRANSFER_ABORTED;
	}

        US_DEBUG(pdump ((void *) fst, partial));

	/* while we haven't recieved the IRQ */
	while (!(fst->Status & 0x2)) {
		/* send a command to re-fetch the status */
		US_DEBUGP("Re-attempting to get status...\n");

		fcb->Type = FCM_PACKET_STATUS;
		fcb->Timeout = 0;
		memset (fcb->Atapi, 0, 12);
		memset (fcb->Filler, 0, sizeof (fcb->Filler));

		/* Send it out. */
		result = usb_stor_bulk_msg (us, fcb, opipe,
				FCM_PACKET_LENGTH, &partial);

		/* The Freecom device will only fail if there is something
		 * wrong in USB land.  It returns the status in its own
		 * registers, which come back in the bulk pipe.
		 */
		if (result != 0) {
			US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
					result, partial);

			/* -ENOENT -- we canceled this transfer */
			if (result == -ENOENT) {
				US_DEBUGP("freecom_transport(): transfer aborted\n");
				return US_BULK_TRANSFER_ABORTED;
			}

			return USB_STOR_TRANSPORT_ERROR;
		}

		/* actually get the status info */
		result = usb_stor_bulk_msg (us, fst, ipipe,
				FCM_PACKET_LENGTH, &partial);
		US_DEBUGP("bar Status result %d %d\n", result, partial);
		/* -ENOENT -- we canceled this transfer */
		if (result == -ENOENT) {
			US_DEBUGP("freecom_transport(): transfer aborted\n");
			return US_BULK_TRANSFER_ABORTED;
		}

		US_DEBUG(pdump ((void *) fst, partial));
	}

        if (partial != 4 || result != 0) {
                return USB_STOR_TRANSPORT_ERROR;
        }
        if ((fst->Status & 1) != 0) {
                US_DEBUGP("operation failed\n");
                return USB_STOR_TRANSPORT_FAILED;
        }

        /* The device might not have as much data available as we
         * requested.  If you ask for more than the device has, this reads
         * and such will hang. */
        US_DEBUGP("Device indicates that it has %d bytes available\n",
                        le16_to_cpu (fst->Count));

        /* Find the length we desire to read.  It is the lesser of the SCSI
         * layer's requested length, and the length the device claims to
         * have available. */
        length = usb_stor_transfer_length (srb);
        US_DEBUGP("SCSI requested %d\n", length);
        if (length > le16_to_cpu (fst->Count))
                length = le16_to_cpu (fst->Count);

        /* What we do now depends on what direction the data is supposed to
         * move in. */

        switch (us->srb->sc_data_direction) {
        case SCSI_DATA_READ:
                /* Make sure that the status indicates that the device
                 * wants data as well. */
                if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
                        US_DEBUGP("SCSI wants data, drive doesn't have any\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }
                result = freecom_readdata (srb, us, ipipe, opipe, length);
                if (result != USB_STOR_TRANSPORT_GOOD)
                        return result;

                US_DEBUGP("FCM: Waiting for status\n");
                result = usb_stor_bulk_msg (us, fst, ipipe,
                                FCM_PACKET_LENGTH, &partial);
		US_DEBUG(pdump ((void *) fst, partial));
                if (result == -ENOENT) {
                        US_DEBUGP ("freecom_transport: transfer aborted\n");
                        return US_BULK_TRANSFER_ABORTED;
                }
                if (partial != 4 || result != 0)
                        return USB_STOR_TRANSPORT_ERROR;
                if ((fst->Status & ERR_STAT) != 0) {
                        US_DEBUGP("operation failed\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }
                if ((fst->Reason & 3) != 3) {
                        US_DEBUGP("Drive seems still hungry\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }
                US_DEBUGP("Transfer happy\n");
                break;

        case SCSI_DATA_WRITE:
                /* Make sure the status indicates that the device wants to
                 * send us data. */
                /* !!IMPLEMENT!! */
                result = freecom_writedata (srb, us, ipipe, opipe, length);
                if (result != USB_STOR_TRANSPORT_GOOD)
                        return result;

#if 1
                US_DEBUGP("FCM: Waiting for status\n");
                result = usb_stor_bulk_msg (us, fst, ipipe,
                                FCM_PACKET_LENGTH, &partial);
                if (result == -ENOENT) {
                        US_DEBUGP ("freecom_transport: transfer aborted\n");
                        return US_BULK_TRANSFER_ABORTED;
                }
                if (partial != 4 || result != 0)
                        return USB_STOR_TRANSPORT_ERROR;
                if ((fst->Status & ERR_STAT) != 0) {
                        US_DEBUGP("operation failed\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }
                if ((fst->Reason & 3) != 3) {
                        US_DEBUGP("Drive seems still hungry\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }
#endif
                US_DEBUGP("Transfer happy\n");
                break;


        case SCSI_DATA_NONE:
                /* Easy, do nothing. */
                break;

        default:
                US_DEBUGP ("freecom unimplemented direction: %d\n",
                                us->srb->sc_data_direction);
                // Return fail, SCSI seems to handle this better.
                return USB_STOR_TRANSPORT_FAILED;
                break;
        }

        return USB_STOR_TRANSPORT_GOOD;

        US_DEBUGP("Freecom: transfer_length = %d\n",
			usb_stor_transfer_length (srb));

        US_DEBUGP("Freecom: direction = %d\n", srb->sc_data_direction);

        return USB_STOR_TRANSPORT_ERROR;
}
Esempio n. 8
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;
    }
}
Esempio n. 9
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;
}
Esempio n. 10
0
/*
 * Transport for the Freecom USB/IDE adaptor.
 *
 */
int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
{
        struct freecom_cb_wrap *fcb;
        struct freecom_status  *fst;
        int ipipe, opipe;             /* We need both pipes. */
        int result;
        int partial;
        int length;
        freecom_udata_t extra;

        extra = (freecom_udata_t) us->extra;

        fcb = (struct freecom_cb_wrap *) extra->buffer;
        fst = (struct freecom_status *) extra->buffer;

        US_DEBUGP("Freecom TRANSPORT STARTED\n");

        /* Get handles for both transports. */
        opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);
        ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in);

        /* The ATAPI Command always goes out first. */
        fcb->Type = FCM_PACKET_ATAPI | 0x00;
        fcb->Timeout = 0;
        memcpy (fcb->Atapi, srb->cmnd, 12);
        memset (fcb->Filler, 0, sizeof (fcb->Filler));

        US_DEBUG(pdump (srb->cmnd, 12));

        /* Send it out. */
        result = usb_stor_bulk_msg (us, fcb, opipe,
                        FCM_PACKET_LENGTH, &partial);

        /* The Freecom device will only fail if there is something wrong in
         * USB land.  It returns the status in its own registers, which
         * come back in the bulk pipe. */
        if (result != 0) {
                US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
                                result, partial);

		/* -ENOENT -- we canceled this transfer */
		if (result == -ENOENT) {
			US_DEBUGP("freecom_transport(): transfer aborted\n");
			return US_BULK_TRANSFER_ABORTED;
		}

                return USB_STOR_TRANSPORT_ERROR;
        }

        /* There are times we can optimize out this status read, but it
         * doesn't hurt us to always do it now. */
        result = usb_stor_bulk_msg (us, fst, ipipe,
                        FCM_PACKET_LENGTH, &partial);
        US_DEBUGP("foo Status result %d %d\n", result, partial);
	/* -ENOENT -- we canceled this transfer */
	if (result == -ENOENT) {
		US_DEBUGP("freecom_transport(): transfer aborted\n");
		return US_BULK_TRANSFER_ABORTED;
	}

        US_DEBUG(pdump ((void *) fst, partial));

	/* The firmware will time-out commands after 20 seconds. Some commands
	 * can legitimately take longer than this, so we use a different
	 * command that only waits for the interrupt and then sends status,
	 * without having to send a new ATAPI command to the device. 
	 *
	 * NOTE: There is some indication that a data transfer after a timeout
	 * may not work, but that is a condition that should never happen.
	 */
	while (fst->Status & FCM_STATUS_BUSY) {
		US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occured!\n");
		US_DEBUGP("fst->Status is %x\n", fst->Status);

		/* Get the status again */
		fcb->Type = FCM_PACKET_STATUS;
		fcb->Timeout = 0;
		memset (fcb->Atapi, 0, sizeof(fcb->Atapi));
		memset (fcb->Filler, 0, sizeof (fcb->Filler));

        	/* Send it out. */
		result = usb_stor_bulk_msg (us, fcb, opipe,
				FCM_PACKET_LENGTH, &partial);

		/* The Freecom device will only fail if there is something
		 * wrong in USB land.  It returns the status in its own
		 * registers, which come back in the bulk pipe.
		 */
		if (result != 0) {
			US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
					result, partial);

			/* -ENOENT -- we canceled this transfer */
			if (result == -ENOENT) {
				US_DEBUGP("freecom_transport(): transfer aborted\n");
				return US_BULK_TRANSFER_ABORTED;
			}

			return USB_STOR_TRANSPORT_ERROR;
		}

		/* get the data */
        	result = usb_stor_bulk_msg (us, fst, ipipe,
				FCM_PACKET_LENGTH, &partial);

		US_DEBUGP("bar Status result %d %d\n", result, partial);

		/* -ENOENT -- we canceled this transfer */
		if (result == -ENOENT) {
			US_DEBUGP("freecom_transport(): transfer aborted\n");
			return US_BULK_TRANSFER_ABORTED;
		}

		US_DEBUG(pdump ((void *) fst, partial));
	}

        if (partial != 4 || result != 0) {
                return USB_STOR_TRANSPORT_ERROR;
        }
        if ((fst->Status & 1) != 0) {
                US_DEBUGP("operation failed\n");
                return USB_STOR_TRANSPORT_FAILED;
        }

        /* The device might not have as much data available as we
         * requested.  If you ask for more than the device has, this reads
         * and such will hang. */
        US_DEBUGP("Device indicates that it has %d bytes available\n",
                        le16_to_cpu (fst->Count));
        US_DEBUGP("SCSI requested %d\n", usb_stor_transfer_length(srb));

        /* Find the length we desire to read. */
	switch (srb->cmnd[0]) {
		case INQUIRY:
		case REQUEST_SENSE:		/* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
		case MODE_SENSE:
		case MODE_SENSE_10:
			length = fst->Count;
			break;
		default:
 			length = usb_stor_transfer_length (srb);
	}

	/* verify that this amount is legal */
	if (length > srb->request_bufflen) {
		length = srb->request_bufflen;
		US_DEBUGP("Truncating request to match buffer length: %d\n", length);
	}

        /* What we do now depends on what direction the data is supposed to
         * move in. */

        switch (us->srb->sc_data_direction) {
        case SCSI_DATA_READ:
                /* Make sure that the status indicates that the device
                 * wants data as well. */
                if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
                        US_DEBUGP("SCSI wants data, drive doesn't have any\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }
                result = freecom_readdata (srb, us, ipipe, opipe, length);
                if (result != USB_STOR_TRANSPORT_GOOD)
                        return result;

                US_DEBUGP("FCM: Waiting for status\n");
                result = usb_stor_bulk_msg (us, fst, ipipe,
                                FCM_PACKET_LENGTH, &partial);
		US_DEBUG(pdump ((void *) fst, partial));
                if (result == -ENOENT) {
                        US_DEBUGP ("freecom_transport: transfer aborted\n");
                        return US_BULK_TRANSFER_ABORTED;
                }
                if (partial != 4 || result != 0)
                        return USB_STOR_TRANSPORT_ERROR;
                if ((fst->Status & ERR_STAT) != 0) {
                        US_DEBUGP("operation failed\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }
                if ((fst->Reason & 3) != 3) {
                        US_DEBUGP("Drive seems still hungry\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }
                US_DEBUGP("Transfer happy\n");
                break;

        case SCSI_DATA_WRITE:
                /* Make sure the status indicates that the device wants to
                 * send us data. */
                /* !!IMPLEMENT!! */
                result = freecom_writedata (srb, us, ipipe, opipe, length);
                if (result != USB_STOR_TRANSPORT_GOOD)
                        return result;

                US_DEBUGP("FCM: Waiting for status\n");
                result = usb_stor_bulk_msg (us, fst, ipipe,
                                FCM_PACKET_LENGTH, &partial);
                if (result == -ENOENT) {
                        US_DEBUGP ("freecom_transport: transfer aborted\n");
                        return US_BULK_TRANSFER_ABORTED;
                }
                if (partial != 4 || result != 0)
                        return USB_STOR_TRANSPORT_ERROR;
                if ((fst->Status & ERR_STAT) != 0) {
                        US_DEBUGP("operation failed\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }
                if ((fst->Reason & 3) != 3) {
                        US_DEBUGP("Drive seems still hungry\n");
                        return USB_STOR_TRANSPORT_FAILED;
                }

                US_DEBUGP("Transfer happy\n");
                break;


        case SCSI_DATA_NONE:
                /* Easy, do nothing. */
                break;

        default:
                US_DEBUGP ("freecom unimplemented direction: %d\n",
                                us->srb->sc_data_direction);
                // Return fail, SCSI seems to handle this better.
                return USB_STOR_TRANSPORT_FAILED;
                break;
        }

        return USB_STOR_TRANSPORT_GOOD;

        US_DEBUGP("Freecom: transfer_length = %d\n",
			usb_stor_transfer_length (srb));

        US_DEBUGP("Freecom: direction = %d\n", srb->sc_data_direction);

        return USB_STOR_TRANSPORT_ERROR;
}