/* Driver for USB Mass Storage compliant devices
 *
 * $Id: transport.c,v 1.2 2004/08/04 01:29:56 joff Exp $
 *
 * Current development and maintenance by:
 *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 *
 * Developed with the assistance of:
 *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
 *   (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
 *   (c) 2002 Alan Stern <stern@rowland.org>
 *
 * Initial work by:
 *   (c) 1999 Michael Gee (michael@linuxspecific.com)
 *
 * This driver is based on the 'USB Mass Storage Class' document. This
 * describes in detail the protocol used to communicate with such
 * devices.  Clearly, the designers had SCSI and ATAPI commands in
 * mind when they created this document.  The commands are all very
 * similar to commands in the SCSI-II and ATAPI specifications.
 *
 * It is important to note that in a number of cases this class
 * exhibits class-specific exemptions from the USB specification.
 * Notably the usage of NAK, STALL and ACK differs from the norm, in
 * that they are used to communicate wait, failed and OK on commands.
 *
 * Also, for certain devices, the interrupt endpoint is used to convey
 * status of a command.
 *
 * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
 * information about this driver.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/config.h>
#include "transport.h"
#include "protocol.h"
#include "usb.h"
#include "debug.h"

#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>

/***********************************************************************
 * Helper routines
 ***********************************************************************/

/* Calculate the length of the data transfer (not the command) for any
 * given SCSI command
 */
unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb)
{
      	int i;
	int doDefault = 0;
	unsigned int len = 0;
	unsigned int total = 0;
	struct scatterlist *sg;

	/* This table tells us:
	   X = command not supported
	   L = return length in cmnd[4] (8 bits).
	   M = return length in cmnd[8] (8 bits).
	   G = return length in cmnd[3] and cmnd[4] (16 bits)
	   H = return length in cmnd[7] and cmnd[8] (16 bits)
	   I = return length in cmnd[8] and cmnd[9] (16 bits)
	   C = return length in cmnd[2] to cmnd[5] (32 bits)
	   D = return length in cmnd[6] to cmnd[9] (32 bits)
	   B = return length in blocksize so we use buff_len
	   R = return length in cmnd[2] to cmnd[4] (24 bits)
	   S = return length in cmnd[3] to cmnd[5] (24 bits)
	   T = return length in cmnd[6] to cmnd[8] (24 bits)
	   U = return length in cmnd[7] to cmnd[9] (24 bits)
	   0-9 = fixed return length
	   V = 20 bytes
	   W = 24 bytes
	   Z = return length is mode dependant or not in command, use buff_len
	*/

	static char *lengths =

	      /* 0123456789ABCDEF   0123456789ABCDEF */

		"00XLZ6XZBXBBXXXB" "00LBBLG0R0L0GG0X"  /* 00-1F */
		"XXXXT8XXB4B0BBBB" "ZZZ0B00HCSSZTBHH"  /* 20-3F */
		"M0HHB0X000H0HH0X" "XHH0HHXX0TH0H0XX"  /* 40-5F */
		"XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX"  /* 60-7F */
		"XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX"  /* 80-9F */
		"X0XXX00XB0BXBXBB" "ZZZ0XUIDU000XHBX"  /* A0-BF */
		"XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX"  /* C0-DF */
		"XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */

	/* Commands checked in table:

	   CHANGE_DEFINITION 40
	   COMPARE 39
	   COPY 18
	   COPY_AND_VERIFY 3a
	   ERASE 19
	   ERASE_10 2c
	   ERASE_12 ac
	   EXCHANGE_MEDIUM a6
	   FORMAT_UNIT 04
	   GET_DATA_BUFFER_STATUS 34
	   GET_MESSAGE_10 28
	   GET_MESSAGE_12 a8
	   GET_WINDOW 25   !!! Has more data than READ_CAPACITY, need to fix table
	   INITIALIZE_ELEMENT_STATUS 07 !!! REASSIGN_BLOCKS luckily uses buff_len
	   INQUIRY 12
	   LOAD_UNLOAD 1b
	   LOCATE 2b
	   LOCK_UNLOCK_CACHE 36
	   LOG_SELECT 4c
	   LOG_SENSE 4d
	   MEDIUM_SCAN 38     !!! This was M
	   MODE_SELECT6 15
	   MODE_SELECT_10 55
	   MODE_SENSE_6 1a
	   MODE_SENSE_10 5a
	   MOVE_MEDIUM a5
	   OBJECT_POSITION 31  !!! Same as SEARCH_DATA_EQUAL
	   PAUSE_RESUME 4b
	   PLAY_AUDIO_10 45
	   PLAY_AUDIO_12 a5
	   PLAY_AUDIO_MSF 47
	   PLAY_AUDIO_TRACK_INDEX 48
   	   PLAY_AUDIO_TRACK_RELATIVE_10 49
	   PLAY_AUDIO_TRACK_RELATIVE_12 a9
	   POSITION_TO_ELEMENT 2b
      	   PRE-FETCH 34
	   PREVENT_ALLOW_MEDIUM_REMOVAL 1e
	   PRINT 0a             !!! Same as WRITE_6 but is always in bytes
	   READ_6 08
	   READ_10 28
	   READ_12 a8
	   READ_BLOCK_LIMITS 05
	   READ_BUFFER 3c
	   READ_CAPACITY 25
	   READ_CDROM_CAPACITY 25
	   READ_DEFECT_DATA 37
	   READ_DEFECT_DATA_12 b7
	   READ_ELEMENT_STATUS b8 !!! Think this is in bytes
	   READ_GENERATION 29 !!! Could also be M?
	   READ_HEADER 44     !!! This was L
	   READ_LONG 3e
	   READ_POSITION 34   !!! This should be V but conflicts with PRE-FETCH
	   READ_REVERSE 0f
	   READ_SUB-CHANNEL 42 !!! Is this in bytes?
	   READ_TOC 43         !!! Is this in bytes?
	   READ_UPDATED_BLOCK 2d
	   REASSIGN_BLOCKS 07
	   RECEIVE 08        !!! Same as READ_6 probably in bytes though
	   RECEIVE_DIAGNOSTIC_RESULTS 1c
	   RECOVER_BUFFERED_DATA 14 !!! For PRINTERs this is bytes
	   RELEASE_UNIT 17
	   REQUEST_SENSE 03
	   REQUEST_VOLUME_ELEMENT_ADDRESS b5 !!! Think this is in bytes
	   RESERVE_UNIT 16
	   REWIND 01
	   REZERO_UNIT 01
	   SCAN 1b          !!! Conflicts with various commands, should be L
	   SEARCH_DATA_EQUAL 31
	   SEARCH_DATA_EQUAL_12 b1
	   SEARCH_DATA_LOW 30
	   SEARCH_DATA_LOW_12 b0
	   SEARCH_DATA_HIGH 32
	   SEARCH_DATA_HIGH_12 b2
	   SEEK_6 0b         !!! Conflicts with SLEW_AND_PRINT
	   SEEK_10 2b
	   SEND 0a           !!! Same as WRITE_6, probably in bytes though
	   SEND 2a           !!! Similar to WRITE_10 but for scanners
	   SEND_DIAGNOSTIC 1d
	   SEND_MESSAGE_6 0a   !!! Same as WRITE_6 - is in bytes
	   SEND_MESSAGE_10 2a  !!! Same as WRITE_10 - is in bytes
	   SEND_MESSAGE_12 aa  !!! Same as WRITE_12 - is in bytes
	   SEND_OPC 54
	   SEND_VOLUME_TAG b6 !!! Think this is in bytes
	   SET_LIMITS 33
	   SET_LIMITS_12 b3
	   SET_WINDOW 24
	   SLEW_AND_PRINT 0b !!! Conflicts with SEEK_6
	   SPACE 11
	   START_STOP_UNIT 1b
	   STOP_PRINT 1b
	   SYNCHRONIZE_BUFFER 10
	   SYNCHRONIZE_CACHE 35
	   TEST_UNIT_READY 00
	   UPDATE_BLOCK 3d
	   VERIFY 13
	   VERIFY 2f
	   VERIFY_12 af
	   WRITE_6 0a
	   WRITE_10 2a
	   WRITE_12 aa
	   WRITE_AND_VERIFY 2e
	   WRITE_AND_VERIFY_12 ae
	   WRITE_BUFFER 3b
	   WRITE_FILEMARKS 10
	   WRITE_LONG 3f
	   WRITE_SAME 41
	*/

	if (srb->sc_data_direction == SCSI_DATA_WRITE) {
		doDefault = 1;
	}
	else
		switch (lengths[srb->cmnd[0]]) {
			case 'L':
				len = srb->cmnd[4];
				break;

			case 'M':
				len = srb->cmnd[8];
				break;

			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				len = lengths[srb->cmnd[0]]-'0';
				break;

			case 'G':
				len = (((unsigned int)srb->cmnd[3])<<8) |
					srb->cmnd[4];
				break;

			case 'H':
				len = (((unsigned int)srb->cmnd[7])<<8) |
					srb->cmnd[8];
				break;

			case 'I':
				len = (((unsigned int)srb->cmnd[8])<<8) |
					srb->cmnd[9];
				break;

			case 'R':
				len = (((unsigned int)srb->cmnd[2])<<16) |
					(((unsigned int)srb->cmnd[3])<<8) |
					srb->cmnd[4];
				break;

			case 'S':
				len = (((unsigned int)srb->cmnd[3])<<16) |
					(((unsigned int)srb->cmnd[4])<<8) |
					srb->cmnd[5];
				break;

			case 'T':
				len = (((unsigned int)srb->cmnd[6])<<16) |
					(((unsigned int)srb->cmnd[7])<<8) |
					srb->cmnd[8];
				break;

			case 'U':
				len = (((unsigned int)srb->cmnd[7])<<16) |
					(((unsigned int)srb->cmnd[8])<<8) |
					srb->cmnd[9];
				break;

			case 'C':
				len = (((unsigned int)srb->cmnd[2])<<24) |
					(((unsigned int)srb->cmnd[3])<<16) |
					(((unsigned int)srb->cmnd[4])<<8) |
					srb->cmnd[5];
				break;

			case 'D':
				len = (((unsigned int)srb->cmnd[6])<<24) |
					(((unsigned int)srb->cmnd[7])<<16) |
					(((unsigned int)srb->cmnd[8])<<8) |
					srb->cmnd[9];
				break;

			case 'V':
				len = 20;
				break;

			case 'W':
				len = 24;
				break;

			case 'B':
				/* Use buffer size due to different block sizes */
				doDefault = 1;
				break;

			case 'X':
				US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
						srb->cmnd[0]);
				doDefault = 1;
				break;

			case 'Z':
				/* Use buffer size due to mode dependence */
				doDefault = 1;
				break;

			default:
				US_DEBUGP("Error: COMMAND %02X out of range or table inconsistent (%c).\n",
						srb->cmnd[0], lengths[srb->cmnd[0]] );
				doDefault = 1;
		}
	   
	   if ( doDefault == 1 ) {
		   /* Are we going to scatter gather? */
		   if (srb->use_sg) {
			   /* Add up the sizes of all the sg segments */
			   sg = (struct scatterlist *) srb->request_buffer;
			   for (i = 0; i < srb->use_sg; i++)
				   total += sg[i].length;
			   len = total;
		   }
		   else
			   /* Just return the length of the buffer */
			   len = srb->request_bufflen;
	   }

	return len;
}

/***********************************************************************
 * Data transfer routines
 ***********************************************************************/

/* This is the completion handler which will wake us up when an URB
 * completes.
 */
static void usb_stor_blocking_completion(struct urb *urb)
{
	struct completion *urb_done_ptr = (struct completion *)urb->context;

	complete(urb_done_ptr);
}

/* This is our function to emulate usb_control_msg() but give us enough
 * access to make aborts/resets work
 */
int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
			 u8 request, u8 requesttype, u16 value, u16 index, 
			 void *data, u16 size)
{
	int status;
	struct usb_ctrlrequest *dr;

	/* allocate the device request structure */
	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
	if (!dr)
		return -ENOMEM;

	/* fill in the structure */
	dr->bRequestType = requesttype;
	dr->bRequest = request;
	dr->wValue = cpu_to_le16(value);
	dr->wIndex = cpu_to_le16(index);
	dr->wLength = cpu_to_le16(size);

	/* set up data structures for the wakeup system */
	init_completion(&us->current_done);

	/* lock the URB */
	down(&(us->current_urb_sem));

	/* fill the URB */
	FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, 
			 (unsigned char*) dr, data, size, 
			 usb_stor_blocking_completion, &us->current_done);
	us->current_urb->actual_length = 0;
	us->current_urb->error_count = 0;
	us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
	us->current_urb->status = 0;

	/* submit the URB */
	status = usb_submit_urb(us->current_urb);
	if (status) {
		/* something went wrong */
		up(&(us->current_urb_sem));
		kfree(dr);
		return status;
	}

	/* wait for the completion of the URB */
	up(&(us->current_urb_sem));
	wait_for_completion(&us->current_done);
	down(&(us->current_urb_sem));

	/* return the actual length of the data transferred if no error*/
	status = us->current_urb->status;
	if (status == -ENOENT)
		status = -ECONNRESET;
	if (status >= 0)
		status = us->current_urb->actual_length;

	/* release the lock and return status */
	up(&(us->current_urb_sem));
	kfree(dr);
  	return status;
}

/* This is our function to emulate usb_bulk_msg() but give us enough
 * access to make aborts/resets work
 */
int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
		      unsigned int len, unsigned int *act_len)
{
	int status;

	/* set up data structures for the wakeup system */
	init_completion(&us->current_done);

	/* lock the URB */
	down(&(us->current_urb_sem));

	/* fill the URB */
	FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,
		      usb_stor_blocking_completion, &us->current_done);
	us->current_urb->actual_length = 0;
	us->current_urb->error_count = 0;
	us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
	us->current_urb->status = 0;

	/* submit the URB */
	status = usb_submit_urb(us->current_urb);
	if (status) {
		/* something went wrong */
		up(&(us->current_urb_sem));
		return status;
	}

	/* wait for the completion of the URB */
	up(&(us->current_urb_sem));
	wait_for_completion(&us->current_done);
	down(&(us->current_urb_sem));
	if (us->current_urb->status == -ENOENT)
		us->current_urb->status = -ECONNRESET;

	/* return the actual length of the data transferred */
	*act_len = us->current_urb->actual_length;

	/* release the lock and return status */
	up(&(us->current_urb_sem));
	return us->current_urb->status;
}

/* This is a version of usb_clear_halt() that doesn't read the status from
 * the device -- this is because some devices crash their internal firmware
 * when the status is requested after a halt
 */
int usb_stor_clear_halt(struct us_data *us, int pipe)
{
	int result;
	int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);

	result = usb_stor_control_msg(us,
		usb_sndctrlpipe(us->pusb_dev, 0),
		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
		endp, NULL, 0);		/* note: no 3*HZ timeout */
	US_DEBUGP("usb_stor_clear_halt: result=%d\n", result);

	/* this is a failure case */
	if (result < 0)
		return result;

	/* reset the toggles and endpoint flags */
	usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe),
		usb_pipeout(pipe));
	usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
		usb_pipeout(pipe), 0);

	return 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;
}

/*
 * 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++) {

			/* transfer the lesser of the next buffer or the
			 * remaining data */
			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;
}

/***********************************************************************
 * Transport routines
 ***********************************************************************/

/* Invoke the transport and basic error-handling/recovery methods
 *
 * This is used by the protocol layers to actually send the message to
 * the device and receive the response.
 */
void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
{
	int need_auto_sense;
	int result;

	/* send the command to the transport layer */
	result = us->transport(srb, us);

	/* if the command gets aborted by the higher layers, we need to
	 * short-circuit all other processing
	 */
	if (result == USB_STOR_TRANSPORT_ABORTED) {
		US_DEBUGP("-- transport indicates command was aborted\n");
		srb->result = DID_ABORT << 16;

		/* Bulk-only aborts require a device reset */
		if (us->protocol == US_PR_BULK)
			us->transport_reset(us);
		return;
	}

	/* if there is a transport error, reset and don't auto-sense */
	if (result == USB_STOR_TRANSPORT_ERROR) {
		US_DEBUGP("-- transport indicates error, resetting\n");
		us->transport_reset(us);
		srb->result = DID_ERROR << 16;
		return;
	}

	/* Determine if we need to auto-sense
	 *
	 * I normally don't use a flag like this, but it's almost impossible
	 * to understand what's going on here if I don't.
	 */
	need_auto_sense = 0;

	/*
	 * If we're running the CB transport, which is incapable
	 * of determining status on it's own, we need to auto-sense almost
	 * every time.
	 */
	if (us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) {
		US_DEBUGP("-- CB transport device requiring auto-sense\n");
		need_auto_sense = 1;

		/* There are some exceptions to this.  Notably, if this is
		 * a UFI device and the command is REQUEST_SENSE or INQUIRY,
		 * then it is impossible to truly determine status.
		 */
		if (us->subclass == US_SC_UFI &&
		    ((srb->cmnd[0] == REQUEST_SENSE) ||
		     (srb->cmnd[0] == INQUIRY))) {
			US_DEBUGP("** no auto-sense for a special command\n");
			need_auto_sense = 0;
		}
	}

	/*
	 * If we have a failure, we're going to do a REQUEST_SENSE 
	 * automatically.  Note that we differentiate between a command
	 * "failure" and an "error" in the transport mechanism.
	 */
	if (result == USB_STOR_TRANSPORT_FAILED) {
		US_DEBUGP("-- transport indicates command failure\n");
		need_auto_sense = 1;
	}

	/*
	 * Also, if we have a short transfer on a command that can't have
	 * a short transfer, we're going to do this.
	 */
	if ((srb->result == US_BULK_TRANSFER_SHORT) &&
	    !((srb->cmnd[0] == REQUEST_SENSE) ||
	      (srb->cmnd[0] == INQUIRY) ||
	      (srb->cmnd[0] == MODE_SENSE) ||
	      (srb->cmnd[0] == LOG_SENSE) ||
	      (srb->cmnd[0] == MODE_SENSE_10))) {
		US_DEBUGP("-- unexpectedly short transfer\n");
		need_auto_sense = 1;
	}

	/* Now, if we need to do the auto-sense, let's do it */
	if (need_auto_sense) {
		int temp_result;
		void* old_request_buffer;
		unsigned short old_sg;
		unsigned old_request_bufflen;
		unsigned char old_sc_data_direction;
		unsigned char old_cmd_len;
		unsigned char old_cmnd[MAX_COMMAND_SIZE];

		US_DEBUGP("Issuing auto-REQUEST_SENSE\n");

		/* save the old command */
		memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
		old_cmd_len = srb->cmd_len;

		/* set the command and the LUN */
		memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
		srb->cmnd[0] = REQUEST_SENSE;
		srb->cmnd[1] = old_cmnd[1] & 0xE0;
		srb->cmnd[4] = 18;

		/* FIXME: we must do the protocol translation here */
		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
			srb->cmd_len = 6;
		else
			srb->cmd_len = 12;

		/* set the transfer direction */
		old_sc_data_direction = srb->sc_data_direction;
		srb->sc_data_direction = SCSI_DATA_READ;

		/* use the new buffer we have */
		old_request_buffer = srb->request_buffer;
		srb->request_buffer = srb->sense_buffer;

		/* set the buffer length for transfer */
		old_request_bufflen = srb->request_bufflen;
		srb->request_bufflen = 18;

		/* set up for no scatter-gather use */
		old_sg = srb->use_sg;
		srb->use_sg = 0;

		/* issue the auto-sense command */
		temp_result = us->transport(us->srb, us);

		/* let's clean up right away */
		srb->request_buffer = old_request_buffer;
		srb->request_bufflen = old_request_bufflen;
		srb->use_sg = old_sg;
		srb->sc_data_direction = old_sc_data_direction;
		srb->cmd_len = old_cmd_len;
		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);

		if (temp_result == USB_STOR_TRANSPORT_ABORTED) {
			US_DEBUGP("-- auto-sense aborted\n");
			srb->result = DID_ABORT << 16;
			return;
		}
		if (temp_result != USB_STOR_TRANSPORT_GOOD) {
			US_DEBUGP("-- auto-sense failure\n");

			/* we skip the reset if this happens to be a
			 * multi-target device, since failure of an
			 * auto-sense is perfectly valid
			 */
			if (!(us->flags & US_FL_SCM_MULT_TARG)) {
				us->transport_reset(us);
			}
			srb->result = DID_ERROR << 16;
			return;
		}

		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
		US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
			  srb->sense_buffer[0],
			  srb->sense_buffer[2] & 0xf,
			  srb->sense_buffer[12], 
			  srb->sense_buffer[13]);
#ifdef CONFIG_USB_STORAGE_DEBUG
		usb_stor_show_sense(
			  srb->sense_buffer[2] & 0xf,
			  srb->sense_buffer[12], 
			  srb->sense_buffer[13]);
#endif

		/* set the result so the higher layers expect this data */
		srb->result = CHECK_CONDITION << 1;

		/* If things are really okay, then let's show that */
		if ((srb->sense_buffer[2] & 0xf) == 0x0)
			srb->result = GOOD << 1;
	} else /* if (need_auto_sense) */
		srb->result = GOOD << 1;

	/* Regardless of auto-sense, if we _know_ we have an error
	 * condition, show that in the result code
	 */
	if (result == USB_STOR_TRANSPORT_FAILED)
		srb->result = CHECK_CONDITION << 1;

	/* If we think we're good, then make sure the sense data shows it.
	 * This is necessary because the auto-sense for some devices always
	 * sets byte 0 == 0x70, even if there is no error
	 */
	if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && 
	    (result == USB_STOR_TRANSPORT_GOOD) &&
	    ((srb->sense_buffer[2] & 0xf) == 0x0))
		srb->sense_buffer[0] = 0x0;
}

/*
 * Control/Bulk/Interrupt transport
 */

/* The interrupt handler for CBI devices */
void usb_stor_CBI_irq(struct urb *urb)
{
	struct us_data *us = (struct us_data *)urb->context;

	US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no);
	US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
	US_DEBUGP("-- IRQ state is %d\n", urb->status);
	US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
			us->irqbuf[0], us->irqbuf[1]);

	/* reject improper IRQs */
	if (urb->actual_length != 2) {
		US_DEBUGP("-- IRQ too short\n");
		return;
	}

	/* is the device removed? */
	if (urb->status == -ENODEV) {
		US_DEBUGP("-- device has been removed\n");
		return;
	}

	/* was this a command-completion interrupt? */
	if (us->irqbuf[0] && (us->subclass != US_SC_UFI)) {
		US_DEBUGP("-- not a command-completion IRQ\n");
		return;
	}

	/* was this a wanted interrupt? */
	if (!atomic_read(us->ip_wanted)) {
		US_DEBUGP("ERROR: Unwanted interrupt received!\n");
		return;
	}

	/* adjust the flag */
	atomic_set(us->ip_wanted, 0);
		
	/* copy the valid data */
	us->irqdata[0] = us->irqbuf[0];
	us->irqdata[1] = us->irqbuf[1];

	/* wake up the command thread */
	US_DEBUGP("-- Current value of ip_waitq is: %d\n",
			atomic_read(&us->ip_waitq.count));
	up(&(us->ip_waitq));
}

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;
}

/*
 * 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;
}

/*
 * Bulk only transport
 */

/* Determine what the maximum LUN supported is */
int usb_stor_Bulk_max_lun(struct us_data *us)
{
	unsigned char *data;
	int result;
	int pipe;

	data = kmalloc(sizeof *data, GFP_KERNEL);
	if (!data) {
		return 0;
	}

	/* issue the command -- use usb_control_msg() because
	 *  the state machine is not yet alive */
	pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
	result = usb_control_msg(us->pusb_dev, pipe,
				 US_BULK_GET_MAX_LUN, 
				 USB_DIR_IN | USB_TYPE_CLASS | 
				 USB_RECIP_INTERFACE,
				 0, us->ifnum, data, sizeof(*data), HZ);

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

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

	/* if we get a STALL, clear the stall */
	if (result == -EPIPE) {
		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);

		/* Use usb_clear_halt() because the state machine
		 *  is not yet alive */
		usb_clear_halt(us->pusb_dev, pipe);
	}

	/* return the default -- no LUNs */
	return 0;
}

int usb_stor_Bulk_reset(struct us_data *us);

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), 
		  le32_to_cpu(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->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_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;
}

/***********************************************************************
 * Reset routines
 ***********************************************************************/

/* This issues a CB[I] Reset to the device in question
 */
int usb_stor_CB_reset(struct us_data *us)
{
	unsigned char cmd[12];
	int result;

	US_DEBUGP("CB_reset() called\n");

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

	memset(cmd, 0xFF, sizeof(cmd));
	cmd[0] = SEND_DIAGNOSTIC;
	cmd[1] = 4;
	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
				 US_CBI_ADSC, 
				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
				 0, us->ifnum, cmd, sizeof(cmd), HZ*5);

	if (result < 0) {
		US_DEBUGP("CB[I] soft reset failed %d\n", result);
		return FAILED;
	}

	/* long wait for reset */
	set_current_state(TASK_UNINTERRUPTIBLE);
	schedule_timeout(HZ*6);
	set_current_state(TASK_RUNNING);

	US_DEBUGP("CB_reset: clearing endpoint halt\n");
	usb_stor_clear_halt(us,
			usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
	usb_stor_clear_halt(us,
			usb_sndbulkpipe(us->pusb_dev, us->ep_out));

	US_DEBUGP("CB_reset done\n");
	/* return a result code based on the result of the control message */
	return SUCCESS;
}

/* This issues a Bulk-only Reset to the device in question, including
 * clearing the subsequent endpoint halts that may occur.
 */
int usb_stor_Bulk_reset(struct us_data *us)
{
	int result;

	US_DEBUGP("Bulk reset requested\n");

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

	result = usb_control_msg(us->pusb_dev, 
				 usb_sndctrlpipe(us->pusb_dev,0), 
				 US_BULK_RESET_REQUEST, 
				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
				 0, us->ifnum, NULL, 0, HZ*5);

	if (result < 0) {
		US_DEBUGP("Bulk soft reset failed %d\n", result);
		return FAILED;
	}

	/* long wait for reset */
	set_current_state(TASK_UNINTERRUPTIBLE);
	schedule_timeout(HZ*6);
	set_current_state(TASK_RUNNING);

	usb_stor_clear_halt(us,
			usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
	usb_stor_clear_halt(us,
			usb_sndbulkpipe(us->pusb_dev, us->ep_out));
	US_DEBUGP("Bulk soft reset completed\n");
	return SUCCESS;
}
