patch-2.4.0-test9 linux/drivers/usb/storage/shuttle_usbat.c

Next file: linux/drivers/usb/storage/shuttle_usbat.h
Previous file: linux/drivers/usb/storage/scsiglue.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/shuttle_usbat.c linux/drivers/usb/storage/shuttle_usbat.c
@@ -1,18 +1,6 @@
 /* Driver for SCM Microsystems USB-ATAPI cable
  *
- * $Id: shuttle_usbat.c,v 1.4 2000/08/25 00:13:51 mdharm Exp $
- *
- * SCM driver v0.2:
- *
- * Removed any reference to maxlen for bulk transfers.
- * Changed scm_bulk_transport to allow for transfers without commands.
- * Changed hp8200e transport to use the request_bufflen field in the
- *   SCSI command for the length of the transfer, rather than calculating
- *   it ourselves based on the command.
- *
- * SCM driver v0.1:
- *
- * First release - hp8200e.
+ * $Id: shuttle_usbat.c,v 1.10 2000/09/24 00:03:08 groovyjava Exp $
  *
  * Current development and maintenance by:
  *   (c) 2000 Robert Baruch (autophile@dol.net)
@@ -30,8 +18,8 @@
  * as well. This driver is only guaranteed to work with the ATAPI
  * translation.
  *
- * The only peripherals that I know of (as of 14 Jul 2000) that uses this
- * device is the Hewlett-Packard 8200e CD-Writer Plus.
+ * The only peripheral that I know of (as of 8 Sep 2000) that uses this
+ * device is the Hewlett-Packard 8200e/8210e CD-Writer Plus.
  *
  * 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
@@ -64,10 +52,12 @@
 extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
 	unsigned int len, unsigned int *act_len);
 
-#define short_pack(b1,b2) ( ((u16)(b1)) | ( ((u16)(b2))<<8 ) )
+#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )
 #define LSB_of(s) ((s)&0xFF)
 #define MSB_of(s) ((s)>>8)
 
+int transferred = 0;
+
 /*
  * Send a control message and wait for the response.
  *
@@ -98,16 +88,6 @@
 
 	int result;
 
-	// If data is going to be sent or received with the URB,
-	// then allocate a buffer for it. If data is to be sent,
-	// copy the data into the buffer.
-/*
-	if (xfer_len > 0) {
-		buffer = kmalloc(xfer_len, GFP_KERNEL);
-		if (!(command[0] & USB_DIR_IN))
-			memcpy(buffer, xfer_data, xfer_len);
-	}
-*/
 	// Send the URB to the device and wait for a response.
 
 	/* Why are request and request type reversed in this call? */
@@ -117,16 +97,6 @@
 			xfer_data, xfer_len);
 
 
-	// If data was sent or received with the URB, free the buffer we
-	// allocated earlier, but not before reading the data out of the
-	// buffer if we wanted to receive data.
-/*
-	if (xfer_len > 0) {
-		if (command[0] & USB_DIR_IN)
-			memcpy(xfer_data, buffer, xfer_len);
-		kfree(buffer);
-	}
-*/
 	// Check the return code for the command.
 
 	if (result < 0) {
@@ -192,7 +162,7 @@
 		if (result == -EPIPE) {
 			US_DEBUGP("usbat_raw_bulk():"
 				" output pipe stalled\n");
-			return USB_STOR_TRANSPORT_FAILED;
+			return US_BULK_TRANSFER_SHORT;
 		}
 
                 /* the catch-all case */
@@ -206,7 +176,8 @@
 		return US_BULK_TRANSFER_SHORT;
 	}
 
-	US_DEBUGP("Transfered %d of %d bytes\n", act_len, len);
+	US_DEBUGP("Transferred %s %d of %d bytes\n", 
+		direction==SCSI_DATA_READ ? "in" : "out", act_len, len);
 
 	return US_BULK_TRANSFER_GOOD;
 }
@@ -225,68 +196,18 @@
 
 	int result = USB_STOR_TRANSPORT_GOOD;
 	int transferred = 0;
-	unsigned char execute[8] = {
-		0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-	};
 	int i;
 	struct scatterlist *sg;
-	char string[64];
-	int pipe;
 
-/*
-	if (command_len != 0) {
-
-		// Fix up the command's data length
-
-		command[6] = len&0xFF;
-		command[7] = (len>>8)&0xFF;
-
-		
-
-		result = usbat_send_control(us, 
-					  execute,
-					  command,
-					  command_len);
-
-		if (result != USB_STOR_TRANSPORT_GOOD)
-			return result;
-	}
-*/
 	if (len==0)
 		return USB_STOR_TRANSPORT_GOOD;
 
-
 	/* transfer the data payload for the command, if there is any */
 
-
 	if (command_len != 0)
 		direction = (command[0]&0x80) ? SCSI_DATA_READ :
 			SCSI_DATA_WRITE;
 
-	if (direction == SCSI_DATA_WRITE) {
-
-		/* Debug-print the first 48 bytes of the write transfer */
-
-		if (!use_sg) {
-			string[0] = 0;
-			for (i=0; i<len && i<48; i++) {
-				sprintf(string+strlen(string), "%02X ",
-				  data[i]);
-				if ((i%16)==15) {
-					US_DEBUGP("%s\n", string);
-					string[0] = 0;
-				}
-			}
-			if (string[0]!=0)
-				US_DEBUGP("%s\n", string);
-		}
-	}
-
-
-	US_DEBUGP("SCM data %s transfer %d sg buffers %d\n",
-		  ( direction==SCSI_DATA_READ ? "in" : "out"),
-		  len, use_sg);
-
 	if (!use_sg)
 		result = usbat_raw_bulk(us, direction, data, len);
 	else {
@@ -311,9 +232,6 @@
 	     unsigned char *content) {
 
 	int result;
-	unsigned char command[8] = {
-		0xC0, access, reg, 0x00, 0x00, 0x00, 0x00, 0x00
-	};
 
 	result = usbat_send_control(us,
 		usb_rcvctrlpipe(us->pusb_dev,0),
@@ -324,8 +242,6 @@
 		content,
 		1);
 		
-	// result =  usbat_send_control(us, command, content, 1);
-
 	return result;
 }
 
@@ -335,9 +251,6 @@
 	     unsigned char content) {
 
 	int result;
-	unsigned char command[8] = {
-		0x40, access|0x01, reg, content, 0x00, 0x00, 0x00, 0x00
-	};
 
 	result = usbat_send_control(us,
 		usb_sndctrlpipe(us->pusb_dev,0),
@@ -348,8 +261,6 @@
 		NULL,
 		0);
 		
-	// result =  usbat_send_control(us, command, NULL, 0);
-
 	return result;
 }
 
@@ -376,8 +287,6 @@
 		command,
 		8);
 		
-	// result =  usbat_bulk_transport(us, command, 8, 0, NULL, 0, 0);
-
 	return result;
 }
 
@@ -409,9 +318,6 @@
 	result = usbat_bulk_transport(us,
 		NULL, 0, SCSI_DATA_READ, content, len, use_sg);
 		
-	// result =  usbat_bulk_transport(us,
-	//	command, 8, 0, content, len, use_sg);
-
 	return result;
 }
 
@@ -420,40 +326,47 @@
  * an error condition.
  */
 
-int usbat_wait_not_busy(struct us_data *us) {
+int usbat_wait_not_busy(struct us_data *us, int minutes) {
 
 	int i;
 	int result;
 	unsigned char status;
 
 	/* Synchronizing cache on a CDR could take a heck of a long time,
-	   but probably not more than 15 minutes or so */
+	 * but probably not more than 10 minutes or so. On the other hand,
+	 * doing a full blank on a CDRW at speed 1 will take about 75
+	 * minutes!
+	 */
+
+	for (i=0; i<1200+minutes*60; i++) {
 
-	for (i=0; i<500; i++) {
  		result = usbat_read(us, USBAT_ATA, 0x17, &status);
-		US_DEBUGP("SCM: Write ATA data status is %02X\n", status);
+
 		if (result!=USB_STOR_TRANSPORT_GOOD)
 			return result;
 		if (status&0x01) // check condition
 			return USB_STOR_TRANSPORT_FAILED;
 		if (status&0x20) // device fault
 			return USB_STOR_TRANSPORT_FAILED;
-		if ((status&0x80)!=0x80) // not busy
-			break;
-		if (i<5)
-			wait_ms(100);
-		else if (i<20)
-			wait_ms(500);
-		else if (i<49)
-			wait_ms(1000);
-		else if (i<499)
-			wait_ms(2000);
-	}
 
-	if (i==500)
-		return USB_STOR_TRANSPORT_FAILED;
+		if ((status&0x80)!=0x80) { // not busy
+			US_DEBUGP("Waited not busy for %d steps\n", i);
+			return USB_STOR_TRANSPORT_GOOD;
+		}
 
-	return USB_STOR_TRANSPORT_GOOD;
+		if (i<500)
+			wait_ms(10); // 5 seconds
+		else if (i<700)
+			wait_ms(50); // 10 seconds
+		else if (i<1200)
+			wait_ms(100); // 50 seconds
+		else
+			wait_ms(1000); // X minutes
+	}
+
+	US_DEBUGP("Waited not busy for %d minutes, timing out.\n",
+		minutes);
+	return USB_STOR_TRANSPORT_FAILED;
 }
 
 int usbat_write_block(struct us_data *us,
@@ -461,7 +374,8 @@
 	     unsigned char reg, 
 	     unsigned char *content,
 	     unsigned short len,
-	     int use_sg) {
+	     int use_sg,
+	     int minutes) {
 
 	int result;
 	unsigned char command[8] = {
@@ -487,115 +401,157 @@
 	if (result != USB_STOR_TRANSPORT_GOOD)
 		return result;
 
-	// result =  usbat_bulk_transport(us,
-	//	command, 8, 0, content, len, use_sg);
-
-	return usbat_wait_not_busy(us);
+	return usbat_wait_not_busy(us, minutes);
 }
 
-int usbat_write_block_test(struct us_data *us,
+int usbat_rw_block_test(struct us_data *us,
 	     unsigned char access,
 	     unsigned char *registers,
 	     unsigned char *data_out,
 	     unsigned short num_registers,
 	     unsigned char data_reg, 
 	     unsigned char status_reg, 
-	     unsigned char qualifier, 
 	     unsigned char timeout, 
+	     unsigned char qualifier, 
+	     int direction,
 	     unsigned char *content,
 	     unsigned short len,
-	     int use_sg) {
+	     int use_sg,
+	     int minutes) {
 
 	int result;
 
 	// Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,
-	// but that's what came out of the trace.
+	// but that's what came out of the trace every single time.
 
 	unsigned char command[16] = {
 		0x40, access|0x07, 0x07, 0x17, 0xfc, 0xe7,
 		LSB_of(num_registers*2), MSB_of(num_registers*2),
-		0x40, access|0x05, data_reg, status_reg,
-		qualifier, timeout, LSB_of(len), MSB_of(len)
+		(direction==SCSI_DATA_WRITE ? 0x40 : 0xC0), 
+		access|(direction==SCSI_DATA_WRITE ? 0x05 : 0x04), 
+		data_reg, status_reg,
+		timeout, qualifier, LSB_of(len), MSB_of(len)
 	};
+
 	int i;
 	unsigned char data[num_registers*2];
-	int transferred;
-	struct scatterlist *sg;
-	char string[64];
+	unsigned char status;
 
 	for (i=0; i<num_registers; i++) {
 		data[i<<1] = registers[i];
 		data[1+(i<<1)] = data_out[i];
 	}
 
-	result = usbat_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
-		0x80,
-		0x40,
-		0,
-		0,
-		command,
-		16);
-
-	if (result != USB_STOR_TRANSPORT_GOOD)
-		return result;
+	for (i=0; i<20; i++) {
 
-	result = usbat_bulk_transport(us,
-		NULL, 0, SCSI_DATA_WRITE, data, num_registers*2, 0);
+		/*
+		 * The first time we send the full command, which consists
+		 * of downloading the SCSI command followed by downloading
+		 * the data via a write-and-test.  Any other time we only
+		 * send the command to download the data -- the SCSI command
+		 * is still 'active' in some sense in the device.
+		 * 
+		 * We're only going to try sending the data 10 times. After
+		 * that, we just return a failure.
+		 */
+
+		result = usbat_send_control(us,
+			  usb_sndctrlpipe(us->pusb_dev,0),
+			0x80,
+			0x40,
+			0,
+			0,
+			(i==0 ? command : command+8),
+			(i==0 ? 16 : 8));
 
-	// result =  usbat_bulk_transport(us,
-	//	command, 16, 0, data, num_registers*2, 0);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			return result;
 
-	if (result!=USB_STOR_TRANSPORT_GOOD)
-		return result;
+		if (i==0) {
 
-	// transferred = 0;
+			result = usbat_bulk_transport(us,
+				NULL, 0, SCSI_DATA_WRITE, 
+				data, num_registers*2, 0);
 
-	US_DEBUGP("Transfer out %d bytes, sg buffers %d\n",
-		len, use_sg);
+			if (result!=USB_STOR_TRANSPORT_GOOD)
+				return result;
 
-	result = usbat_bulk_transport(us,
-		NULL, 0, SCSI_DATA_WRITE, content, len, use_sg);
+		}
 
-/*
-	if (!use_sg) {
 
-		// Debug-print the first 48 bytes of the transfer
+		//US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n",
+		//	direction == SCSI_DATA_WRITE ? "out" : "in",
+		//	len, use_sg);
+
+		result = usbat_bulk_transport(us,
+			NULL, 0, direction, content, len, use_sg);
+
+		/*
+		 * If we get a stall on the bulk download, we'll retry
+		 * the bulk download -- but not the SCSI command because
+		 * in some sense the SCSI command is still 'active' and
+		 * waiting for the data. Don't ask me why this should be;
+		 * I'm only following what the Windoze driver did.
+		 *
+		 * Note that a stall for the test-and-read/write command means
+		 * that the test failed. In this case we're testing to make
+		 * sure that the device is error-free
+		 * (i.e. bit 0 -- CHK -- of status is 0). The most likely
+		 * hypothesis is that the USBAT chip somehow knows what
+		 * the device will accept, but doesn't give the device any
+		 * data until all data is received. Thus, the device would
+		 * still be waiting for the first byte of data if a stall
+		 * occurs, even if the stall implies that some data was
+		 * transferred.
+		 */
+
+		if (result == US_BULK_TRANSFER_SHORT) {
+
+			/*
+			 * If we're reading and we stalled, then clear
+			 * the bulk output pipe only the first time.
+			 */
+
+			if (direction==SCSI_DATA_READ && i==0)
+				usb_clear_halt(us->pusb_dev,
+					usb_sndbulkpipe(us->pusb_dev,
+					  us->ep_out));
+			/*
+			 * Read status: is the device angry, or just busy?
+			 */
+
+ 			result = usbat_read(us, USBAT_ATA, 
+				direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, 
+				&status);
 
-		string[0] = 0;
-		for (i=0; i<len && i<48; i++) {
-			sprintf(string+strlen(string), "%02X ",
-				content[i]);
-			if ((i%16)==15) {
-				US_DEBUGP("%s\n", string);
-				string[0] = 0;
-			}
-		}
-		if (string[0]!=0)
-			US_DEBUGP("%s\n", string);
+			if (result!=USB_STOR_TRANSPORT_GOOD)
+				return result;
+			if (status&0x01) // check condition
+				return USB_STOR_TRANSPORT_FAILED;
+			if (status&0x20) // device fault
+				return USB_STOR_TRANSPORT_FAILED;
 
-		result = usbat_raw_bulk(us, SCSI_DATA_WRITE, content, len);
+			US_DEBUGP("Redoing %s\n",
+			  direction==SCSI_DATA_WRITE ? "write" : "read");
 
-	} else {
+		} else if (result != US_BULK_TRANSFER_GOOD)
+			return result;
+		else
+			return usbat_wait_not_busy(us, minutes);
 
-		sg = (struct scatterlist *)content;
-		for (i=0; i<use_sg && transferred<len; i++) {
-			result = usbat_raw_bulk(us, SCSI_DATA_WRITE,
-				sg[i].address, 
-				len-transferred > sg[i].length ?
-					sg[i].length : len-transferred);
-			if (result!=US_BULK_TRANSFER_GOOD)
-				break;
-			transferred += sg[i].length;
-		}
 	}
-*/
-	if (result!=USB_STOR_TRANSPORT_GOOD)
-		return result;
 
-	return usbat_wait_not_busy(us);
+	US_DEBUGP("Bummer! %s bulk data 20 times failed.\n",
+		direction==SCSI_DATA_WRITE ? "Writing" : "Reading");
+
+	return USB_STOR_TRANSPORT_FAILED;
 }
 
+/*
+ * Write data to multiple registers at once. Not meant for large
+ * transfers of data!
+ */
+
 int usbat_multiple_write(struct us_data *us, 
 			unsigned char access,
 			unsigned char *registers,
@@ -630,21 +586,15 @@
 	result = usbat_bulk_transport(us,
 		NULL, 0, SCSI_DATA_WRITE, data, num_registers*2, 0);
 
-	// result = usbat_bulk_transport(us, cmd, 8, 0, 
-	//	data, num_registers*2, 0);
-
 	if (result!=USB_STOR_TRANSPORT_GOOD)
 		return result;
 
-	return usbat_wait_not_busy(us);
+	return usbat_wait_not_busy(us, 0);
 }
 
 int usbat_read_user_io(struct us_data *us,
 		unsigned char *data_flags) {
 
-	unsigned char command[8] = {
-		0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-	};
 	int result;
 
 	result = usbat_send_control(us,
@@ -656,8 +606,6 @@
 		data_flags,
 		1);
 		
-	// result = usbat_send_control(us, command, data_flags, 1);
-
 	return result;
 }
 
@@ -665,9 +613,6 @@
 		unsigned char enable_flags,
 		unsigned char data_flags) {
 
-	unsigned char command[8] = {
-		0x40, 0x82, enable_flags, data_flags, 0x00, 0x00, 0x00, 0x00
-	};
 	int result;
 
 	result = usbat_send_control(us,
@@ -679,8 +624,138 @@
 		NULL,
 		0);
 		
-	// result = usbat_send_control(us, command, NULL, 0);
+	return result;
+}
+
+/*
+ * Squeeze a potentially huge (> 65535 byte) read10 command into
+ * a little ( <= 65535 byte) ATAPI pipe
+ */
+
+int usbat_handle_read10(struct us_data *us,
+		unsigned char *registers,
+		unsigned char *data,
+		Scsi_Cmnd *srb) {
+
+	int result = USB_STOR_TRANSPORT_GOOD;
+	unsigned char *buffer;
+	unsigned int len;
+	unsigned int sector;
+	unsigned int amount;
+	struct scatterlist *sg = NULL;
+	int sg_segment = 0;
+	int sg_offset = 0;
+
+	US_DEBUGP("handle_read10: transfersize %d\n",
+		srb->transfersize);
+
+	if (srb->request_bufflen < 0x10000) {
+
+		result = usbat_rw_block_test(us, USBAT_ATA, 
+			registers, data, 19,
+			0x10, 0x17, 0xFD, 0x30,
+			SCSI_DATA_READ,
+			srb->request_buffer, 
+			srb->request_bufflen, srb->use_sg, 1);
+
+		return result;
+	}
+
+	/*
+	 * Since we're requesting more data than we can handle in
+	 * a single read command (max is 64k-1), we will perform
+	 * multiple reads, but each read must be in multiples of
+	 * a sector.  Luckily the sector size is in srb->transfersize
+	 * (see linux/drivers/scsi/sr.c).
+	 */
+
+	if (data[7+0] == GPCMD_READ_CD) {
+		len = short_pack(data[7+9], data[7+8]);
+		len <<= 16;
+		len |= data[7+7];
+		srb->transfersize = srb->request_bufflen/len;
+	}
+
+	
+	len = (65535/srb->transfersize) * srb->transfersize;
+	US_DEBUGP("Max read is %d bytes\n", len);
+	buffer = kmalloc(len, GFP_KERNEL);
+	if (buffer == NULL) // bloody hell!
+		return USB_STOR_TRANSPORT_FAILED;
+	sector = short_pack(data[7+3], data[7+2]);
+	sector <<= 16;
+	sector |= short_pack(data[7+5], data[7+4]);
+	transferred = 0;
+
+	if (srb->use_sg) {
+		sg = (struct scatterlist *)srb->request_buffer;
+		sg_segment = 0; // for keeping track of where we are in
+		sg_offset = 0;  // the scatter/gather list
+	}
+
+	while (transferred != srb->request_bufflen) {
+		
+		if (len > srb->request_bufflen - transferred)
+			len = srb->request_bufflen - transferred;
+
+		data[3] = len&0xFF; 	  // (cylL) = expected length (L)
+		data[4] = (len>>8)&0xFF;  // (cylH) = expected length (H)
+
+		// Fix up the SCSI command sector and num sectors
+
+		data[7+2] = MSB_of(sector>>16); // SCSI command sector
+		data[7+3] = LSB_of(sector>>16);
+		data[7+4] = MSB_of(sector&0xFFFF);
+		data[7+5] = LSB_of(sector&0xFFFF);
+		if (data[7+0] == GPCMD_READ_CD)
+			data[7+6] = 0;
+		data[7+7] = MSB_of(len / srb->transfersize); // SCSI command
+		data[7+8] = LSB_of(len / srb->transfersize); // num sectors
+		
+		result = usbat_rw_block_test(us, USBAT_ATA, 
+			registers, data, 19,
+			0x10, 0x17, 0xFD, 0x30,
+			SCSI_DATA_READ,
+			buffer,
+			len, 0, 1);
+
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			break;
+
+		// Transfer the received data into the srb buffer
+
+		if (!srb->use_sg) {
+			memcpy(srb->request_buffer+transferred, buffer, len);
+		} else {
+			amount = 0;
+			while (amount<len) {
+				if (len - amount >= 
+					  sg[sg_segment].length-sg_offset) {
+				  memcpy(sg[sg_segment].address + sg_offset,
+					buffer + amount,
+					sg[sg_segment].length - sg_offset);
+				  amount += 
+					  sg[sg_segment].length-sg_offset;
+				  sg_segment++;
+				  sg_offset=0;
+				} else {
+				  memcpy(sg[sg_segment].address + sg_offset,
+					buffer + amount,
+					len - amount);
+				  sg_offset += (len - amount);
+				  amount = len;
+				}
+			}
+		}
 
+		// Update the amount transferred and the sector number
+
+		transferred += len;
+		sector += len / srb->transfersize;
+
+	} // while transferred != srb->request_bufflen
+
+	kfree(buffer);
 	return result;
 }
 
@@ -870,102 +945,8 @@
 	int i;
 	char string[64];
 
-	/* This table tells us:
-	   X = command not supported
-	   L = return length in cmnd[4] (8 bits).
-	   H = return length in cmnd[7] and cmnd[8] (16 bits).
-	   D = return length in cmnd[6] to cmnd[9] (32 bits).
-	   B = return length/blocksize in cmnd[6] to cmnd[8].
-	   T = return length in cmnd[6] to cmnd[8] (24 bits).
-	   0-9 = fixed return length
-	   W = 24 bytes
-	   h = return length/2048 in cmnd[7-8].
-	*/
-
-	static char *lengths =
-
-	/* 0123456789ABCDEF   0123456789ABCDEF */
-
-	  "0XXL0XXXXXXXXXXX" "XXLXXXXXXXX0XX0X"  /* 00-1F */
-	  "XXXXX8XXhXH0XXX0" "XXXXX0XXXXXXXXXX"  /* 20-3F */
-	  "XXHHL0X0XXH0XX0X" "XHH00HXX0TH0H0XX"  /* 40-5F */
-	  "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX"  /* 60-7F */
-	  "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX"  /* 80-9F */
-	  "X0XXX0XXDXDXXXXX" "XXXXXXXXX000XHBX"  /* A0-BF */
-	  "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX"  /* C0-DF */
-	  "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */
-
-/*	if (us->flags & US_FL_NEED_INIT) {
-		US_DEBUGP("8200e: initializing\n");
-		init_8200e(us);
-		us->flags &= ~US_FL_NEED_INIT;
-	} */
-
 	len = srb->request_bufflen;
 
-/*	if (srb->sc_data_direction == SCSI_DATA_WRITE)
-		len = srb->request_bufflen;
-	else {
-
-		switch (lengths[srb->cmnd[0]]) {
-
-		case 'L':
-			len = srb->cmnd[4];
-			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 'H':
-			len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
-			break;
-		case 'h':
-			len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
-			len <<= 11; // *2048
-			break;
-		case 'T':
-			len = (((unsigned int)srb->cmnd[6])<<16) |
-			      (((unsigned int)srb->cmnd[7])<<8) |
-			      srb->cmnd[8];
-			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 'W':
-			len = 24;
-			break;
-		case 'B':
-			// Let's try using the command structure's
-			//   request_bufflen here 
-			len = srb->request_bufflen;
-			break;
-		default:
-			US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
-				srb->cmnd[0]);
-			return USB_STOR_TRANSPORT_ERROR;
-		}
-	} */
-
-	if (len > 0xFFFF) {
-		US_DEBUGP("Error: len = %08X... what do I do now?\n",
-			len);
-		return USB_STOR_TRANSPORT_ERROR;
-	}
-
-	// US_DEBUGP("XXXXXXXXXXXXXXXX req_bufflen %d, len %d, bufflen %d\n", 
- 	//	srb->request_bufflen, len, srb->bufflen);
-
 	/* Send A0 (ATA PACKET COMMAND).
 	   Note: I guess we're never going to get any of the ATA
 	   commands... just ATA Packet Commands.
@@ -986,20 +967,41 @@
 	data[5] = 0xB0; 		// (device sel) = slave
 	data[6] = 0xA0; 		// (command) = ATA PACKET COMMAND
 
-	if (srb->sc_data_direction == SCSI_DATA_WRITE) {
+	for (i=7; i<19; i++) {
+		registers[i] = 0x10;
+		data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
+	}
 
-		for (i=7; i<19; i++) {
-			registers[i] = 0x10;
-			data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
-		}
+	if (srb->cmnd[0] == TEST_UNIT_READY)
+		transferred = 0;
+
+	if (srb->sc_data_direction == SCSI_DATA_WRITE) {
 
-		result = usbat_write_block_test(us, USBAT_ATA, 
+		result = usbat_rw_block_test(us, USBAT_ATA, 
 			registers, data, 19,
 			0x10, 0x17, 0xFD, 0x30,
+			SCSI_DATA_WRITE,
 			srb->request_buffer, 
-			len, srb->use_sg);
+			len, srb->use_sg, 10);
+
+		if (result == USB_STOR_TRANSPORT_GOOD) {
+			transferred += len;
+			US_DEBUGP("Wrote %08X bytes\n", transferred);
+		}
 
 		return result;
+
+	} else if (srb->cmnd[0] == READ_10 ||
+		   srb->cmnd[0] == GPCMD_READ_CD) {
+
+		return usbat_handle_read10(us, registers, data, srb);
+
+	}
+
+	if (len > 0xFFFF) {
+		US_DEBUGP("Error: len = %08X... what do I do now?\n",
+			len);
+		return USB_STOR_TRANSPORT_ERROR;
 	}
 
 	if ( (result = usbat_multiple_write(us, 
@@ -1010,8 +1012,15 @@
 
 	// Write the 12-byte command header.
 
+	// If the command is BLANK then set the timer for 75 minutes.
+	// Otherwise set it for 10 minutes.
+
+	// NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW
+	// AT SPEED 4 IS UNRELIABLE!!!
+
 	if ( (result = usbat_write_block(us, 
-			USBAT_ATA, 0x10, srb->cmnd, 12, 0)) !=
+			USBAT_ATA, 0x10, srb->cmnd, 12, 0,
+			srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) !=
 				USB_STOR_TRANSPORT_GOOD) {
 		return result;
 	}
@@ -1060,8 +1069,6 @@
 				US_DEBUGP("%s\n", string);
 		}
 	}
-
-	// US_DEBUGP("Command result %d\n", result);
 
 	return result;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)