Ejemplo n.º 1
0
/* Read a value from an ide register. */
static int
freecom_ide_read (struct us_data *us, int reg, int *value)
{
        freecom_udata_t extra = (freecom_udata_t) us->extra;
        struct freecom_ide_in *idein =
                (struct freecom_ide_in *) extra->buffer;
        __u8 *buffer = extra->buffer;
        int ipipe, opipe;
        int result, partial;
        int desired_length;

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

        if (reg < 0 || reg > 8)
                return USB_STOR_TRANSPORT_ERROR;
        if (reg < 8)
                reg |= 0x10;
        else
                reg = 0x0e;

        US_DEBUGP("IDE in request for register 0x%02x\n", reg);

        idein->Type = FCM_PACKET_IDE_READ | reg;
        memset (idein->Pad, 0, sizeof (idein->Pad));

        result = usb_stor_bulk_msg (us, idein, opipe,
                        FCM_PACKET_LENGTH, &partial);
        if (result != 0) {
                if (result == -ENOENT)
                        return US_BULK_TRANSFER_ABORTED;
                else
                        return USB_STOR_TRANSPORT_ERROR;
        }

        desired_length = 1;
        if (reg == 0x10)
                desired_length = 2;

        result = usb_stor_bulk_msg (us, buffer, ipipe,
                        desired_length, &partial);
        if (result != 0) {
                if (result == -ENOENT)
                        return US_BULK_TRANSFER_ABORTED;
                else
                        return USB_STOR_TRANSPORT_ERROR;
        }
        US_DEBUGP("IDE in partial is %d\n", partial);

        if (desired_length == 1)
                *value = buffer[0];
        else
                *value = le16_to_cpu (*(__u16 *) buffer);

        US_DEBUGP("IDE in 0x%02x -> 0x%02x\n", reg, *value);

        return USB_STOR_TRANSPORT_GOOD;
}
int usb_stor_ucr61s2b_init(struct us_data *us)
{
	int pipe;
	struct bulk_cb_wrap *bcb;
	struct bulk_cs_wrap *bcs;
	int res, partial;

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

	US_DEBUGP("Sending UCR-61S2B initialization packet...\n");

	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
	bcb->Tag = ++(us->tag);
	bcb->DataTransferLength = cpu_to_le32(0);
	bcb->Flags = bcb->Lun = 0;
	bcb->Length = sizeof(UCR61S2B_INIT);
	memset(bcb->CDB, 0, sizeof(bcb->CDB));
	memcpy(bcb->CDB, UCR61S2B_INIT, sizeof(UCR61S2B_INIT));

	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
	res = usb_stor_bulk_msg(us, bcb, pipe, US_BULK_CB_WRAP_LEN, &partial);
	US_DEBUGP("-- result is %d\n", res);
	kfree(bcb);

	if(res) {
		kfree(bcs);
		return(res);
	}

	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
	res = usb_stor_bulk_msg(us, bcs, pipe, US_BULK_CS_WRAP_LEN, &partial);
	US_DEBUGP("-- result of status read is %d\n", res);

	kfree(bcs);

	return(res ? -1 : 0);
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 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.
 */
int usb_stor_transfer_partial(struct us_data *us, char *buf, int length)
{
	int result;
	int partial;
	int pipe;

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

	/* transfer the data */
	US_DEBUGP("usb_stor_transfer_partial(): xfer %d bytes\n", length);
	result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);
	US_DEBUGP("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 == -EPIPE) {
		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
		usb_stor_clear_halt(us, pipe);
	}

	/* did we abort this command? */
	if (result == -ECONNRESET) {
		US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n");
		return US_BULK_TRANSFER_ABORTED;
	}

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

	/* NAK - that means we've retried a few times already */
	if (result == -ETIMEDOUT) {
		US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");
		return US_BULK_TRANSFER_FAILED;
	}

	/* the catch-all error case */
	if (result) {
		US_DEBUGP("usb_stor_transfer_partial(): unknown error\n");
		return US_BULK_TRANSFER_FAILED;
	}

	/* no error code, so we must have transferred some data, 
	 * just not all of it */
	return US_BULK_TRANSFER_SHORT;
}
Ejemplo n.º 5
0
static int
freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
                int ipipe, int opipe, int count)
{
        freecom_udata_t extra = (freecom_udata_t) us->extra;
        struct freecom_xfer_wrap *fxfr =
                (struct freecom_xfer_wrap *) extra->buffer;
        int result, partial;

        fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
        fxfr->Timeout = 0;    /* Short timeout for debugging. */
        fxfr->Count = cpu_to_le32 (count);
        memset (fxfr->Pad, 0, sizeof (fxfr->Pad));

        US_DEBUGP("Write data Freecom! (c=%d)\n", count);

        /* Issue the transfer command. */
        result = usb_stor_bulk_msg (us, fxfr, opipe,
                        FCM_PACKET_LENGTH, &partial);
        if (result != 0) {
                US_DEBUGP ("Freecom writedata xpot failure: r=%d, p=%d\n",
                                result, partial);

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

                return USB_STOR_TRANSPORT_ERROR;
        }
        US_DEBUGP("Done issuing write request: %d %d\n",
                        result, partial);

        /* Now transfer all of our blocks. */
	US_DEBUGP("Start of write\n");
	us_transfer_freecom(srb, us, count);

        US_DEBUGP("freecom_writedata done!\n");
        return USB_STOR_TRANSPORT_GOOD;
}
Ejemplo n.º 6
0
/* Write a value to an ide register. */
static int
freecom_ide_write (struct us_data *us, int reg, int value)
{
        freecom_udata_t extra = (freecom_udata_t) us->extra;
        struct freecom_ide_out *ideout =
                (struct freecom_ide_out *) extra->buffer;
        int opipe;
        int result, partial;

        US_DEBUGP("IDE out 0x%02x <- 0x%02x\n", reg, value);

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

        if (reg < 0 || reg > 8)
                return USB_STOR_TRANSPORT_ERROR;
        if (reg < 8)
                reg |= 0x20;
        else
                reg = 0x0e;

        ideout->Type = FCM_PACKET_IDE_WRITE | reg;
        ideout->Pad = 0;
        ideout->Value = cpu_to_le16 (value);
        memset (ideout->Pad2, 0, sizeof (ideout->Pad2));

        result = usb_stor_bulk_msg (us, ideout, opipe,
                        FCM_PACKET_LENGTH, &partial);
        if (result != 0) {
                if (result == -ENOENT)
                        return US_BULK_TRANSFER_ABORTED;
                else
                        return USB_STOR_TRANSPORT_ERROR;
        }

        return USB_STOR_TRANSPORT_GOOD;
}
static int sddr55_raw_bulk(struct us_data *us, 
		int direction,
		unsigned char *data,
		unsigned int len) {

	int result;
	int act_len;
	int pipe;

	if (direction == SCSI_DATA_READ)
		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
	else
		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);

	result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);

	/* if we stall, we need to clear it before we go on */
	if (result == -EPIPE) {
		US_DEBUGP("EPIPE: clearing endpoint halt for"
			" pipe 0x%x, stalled at %d bytes\n",
			pipe, act_len);
		usb_clear_halt(us->pusb_dev, pipe);
	}

	if (result) {

		/* NAK - that means we've retried a few times already */
		if (result == -ETIMEDOUT) {
			US_DEBUGP("usbat_raw_bulk():"
				" device NAKed\n");

			return US_BULK_TRANSFER_FAILED;
		}

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

		if (result == -EPIPE) {
			US_DEBUGP("usbat_raw_bulk():"
				" output pipe stalled\n");
			return US_BULK_TRANSFER_FAILED;
		}

		/* the catch-all case */
		US_DEBUGP("us_transfer_partial(): unknown error\n");
		return US_BULK_TRANSFER_FAILED;
	}

	if (act_len != len) {
		US_DEBUGP("Warning: Transferred only %d bytes\n",
			act_len);
		return US_BULK_TRANSFER_SHORT;
	}

	US_DEBUGP("Transferred %d of %d bytes\n", act_len, len);

	return US_BULK_TRANSFER_GOOD;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
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;
}