ChangeSet 1.1474.81.31, 2004/01/16 17:11:49-08:00, stern@rowland.harvard.edu

[PATCH] USB Storage: Fix scatter-gather for non READ/WRITE in jumpshot

These patch fixes the scatter-gather usage in the jumpshot driver for
commands other than READ or WRITE.  It also tidies up the MODE-SENSE
handler considerably and reports more command failures correctly.


 drivers/usb/storage/jumpshot.c |  123 ++++++++++++++++-------------------------
 1 files changed, 48 insertions(+), 75 deletions(-)


diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
--- a/drivers/usb/storage/jumpshot.c	Tue Jan 20 17:34:38 2004
+++ b/drivers/usb/storage/jumpshot.c	Tue Jan 20 17:34:38 2004
@@ -43,8 +43,8 @@
   *
   * This driver supports reading and writing.  If you're truly paranoid,
   * however, you can force the driver into a write-protected state by setting
-  * the WP enable bits in jumpshot_handle_mode_sense.  Basically this means
-  * setting mode_param_header[3] = 0x80.  
+  * the WP enable bits in jumpshot_handle_mode_sense.  See the comments
+  * in that routine.
   */
 
 #include "transport.h"
@@ -320,34 +320,24 @@
 
 static int jumpshot_handle_mode_sense(struct us_data *us,
 				      Scsi_Cmnd * srb, 
-				      unsigned char *ptr,
 				      int sense_6)
 {
-	unsigned char mode_param_header[8] = {
-		0, 0, 0, 0, 0, 0, 0, 0
-	};
-	unsigned char rw_err_page[12] = {
+	static unsigned char rw_err_page[12] = {
 		0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
 	};
-	unsigned char cache_page[12] = {
+	static unsigned char cache_page[12] = {
 		0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
 	};
-	unsigned char rbac_page[12] = {
+	static unsigned char rbac_page[12] = {
 		0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
 	};
-	unsigned char timer_page[8] = {
+	static unsigned char timer_page[8] = {
 		0x1C, 0x6, 0, 0, 0, 0
 	};
 	unsigned char pc, page_code;
-	unsigned short total_len = 0;
-	unsigned short param_len, i = 0;
-
-
-	if (sense_6)
-		param_len = srb->cmnd[4];
-	else
-		param_len = ((u32) (srb->cmnd[7]) >> 8) | ((u32) (srb->cmnd[8]));
-
+	unsigned int i = 0;
+	struct jumpshot_info *info = (struct jumpshot_info *) (us->extra);
+	unsigned char *ptr = us->iobuf;
 
 	pc = srb->cmnd[2] >> 6;
 	page_code = srb->cmnd[2] & 0x3F;
@@ -367,66 +357,44 @@
 		break;
 	}
 
-	mode_param_header[3] = 0x80;	// write enable
+	memset(ptr, 0, 8);
+	if (sense_6) {
+		ptr[2] = 0x00;		// WP enable: 0x80
+		i = 4;
+	} else {
+		ptr[3] = 0x00;		// WP enable: 0x80
+		i = 8;
+	}
 
 	switch (page_code) {
 	   case 0x0:
 		// vendor-specific mode
-		return USB_STOR_TRANSPORT_ERROR;
+		info->sense_key = 0x05;
+		info->sense_asc = 0x24;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
 
 	   case 0x1:
-		total_len = sizeof(rw_err_page);
-		mode_param_header[0] = total_len >> 8;
-		mode_param_header[1] = total_len & 0xFF;
-		mode_param_header[3] = 0x00;	// WP enable: 0x80
-
-		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
-		i += sizeof(mode_param_header);
 		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
 		break;
 
 	   case 0x8:
-		total_len = sizeof(cache_page);
-		mode_param_header[0] = total_len >> 8;
-		mode_param_header[1] = total_len & 0xFF;
-		mode_param_header[3] = 0x00;	// WP enable: 0x80
-
-		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
-		i += sizeof(mode_param_header);
 		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
 		break;
 
 	   case 0x1B:
-		total_len = sizeof(rbac_page);
-		mode_param_header[0] = total_len >> 8;
-		mode_param_header[1] = total_len & 0xFF;
-		mode_param_header[3] = 0x00;	// WP enable: 0x80
-
-		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
-		i += sizeof(mode_param_header);
 		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
 		break;
 
 	   case 0x1C:
-		total_len = sizeof(timer_page);
-		mode_param_header[0] = total_len >> 8;
-		mode_param_header[1] = total_len & 0xFF;
-		mode_param_header[3] = 0x00;	// WP enable: 0x80
-
-		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
-		i += sizeof(mode_param_header);
 		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
 		break;
 
 	   case 0x3F:
-		total_len = sizeof(timer_page) + sizeof(rbac_page) +
-		    sizeof(cache_page) + sizeof(rw_err_page);
-		mode_param_header[0] = total_len >> 8;
-		mode_param_header[1] = total_len & 0xFF;
-		mode_param_header[3] = 0x00;	// WP enable: 0x80
-
-		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
-		i += sizeof(mode_param_header);
 		memcpy(ptr + i, timer_page, sizeof(timer_page));
 		i += sizeof(timer_page);
 		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
@@ -434,9 +402,16 @@
 		memcpy(ptr + i, cache_page, sizeof(cache_page));
 		i += sizeof(cache_page);
 		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
 		break;
 	}
 
+	if (sense_6)
+		ptr[0] = i - 1;
+	else
+		((u16 *) ptr)[0] = cpu_to_be16(i - 2);
+	usb_stor_set_xfer_buf(ptr, i, srb);
+
 	return USB_STOR_TRANSPORT_GOOD;
 }
 
@@ -456,8 +431,8 @@
 	struct jumpshot_info *info;
 	int rc;
 	unsigned long block, blocks;
-	unsigned char *ptr = NULL;
-	unsigned char inquiry_response[36] = {
+	unsigned char *ptr = us->iobuf;
+	static unsigned char inquiry_response[8] = {
 		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
 	};
 
@@ -472,12 +447,11 @@
 	}
 
 	info = (struct jumpshot_info *) (us->extra);
-	ptr = (unsigned char *) srb->request_buffer;
 
 	if (srb->cmnd[0] == INQUIRY) {
 		US_DEBUGP("jumpshot_transport:  INQUIRY.  Returning bogus response.\n");
-		memset(inquiry_response + 8, 0, 28);
-		fill_inquiry_response(us, inquiry_response, 36);
+		memcpy(ptr, inquiry_response, sizeof(inquiry_response));
+		fill_inquiry_response(us, ptr, 36);
 		return USB_STOR_TRANSPORT_GOOD;
 	}
 
@@ -497,15 +471,9 @@
 
 		// build the reply
 		//
-		ptr[0] = (info->sectors >> 24) & 0xFF;
-		ptr[1] = (info->sectors >> 16) & 0xFF;
-		ptr[2] = (info->sectors >> 8) & 0xFF;
-		ptr[3] = (info->sectors) & 0xFF;
-
-		ptr[4] = (info->ssize >> 24) & 0xFF;
-		ptr[5] = (info->ssize >> 16) & 0xFF;
-		ptr[6] = (info->ssize >> 8) & 0xFF;
-		ptr[7] = (info->ssize) & 0xFF;
+		((u32 *) ptr)[0] = cpu_to_be32(info->sectors);
+		((u32 *) ptr)[1] = cpu_to_be32(info->ssize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
 
 		return USB_STOR_TRANSPORT_GOOD;
 	}
@@ -568,25 +536,27 @@
 	}
 
 	if (srb->cmnd[0] == REQUEST_SENSE) {
-		US_DEBUGP("jumpshot_transport:  REQUEST_SENSE.  Returning NO SENSE for now\n");
+		US_DEBUGP("jumpshot_transport:  REQUEST_SENSE.\n");
 
+		memset(ptr, 0, 18);
 		ptr[0] = 0xF0;
 		ptr[2] = info->sense_key;
 		ptr[7] = 11;
 		ptr[12] = info->sense_asc;
 		ptr[13] = info->sense_ascq;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
 
 		return USB_STOR_TRANSPORT_GOOD;
 	}
 
 	if (srb->cmnd[0] == MODE_SENSE) {
 		US_DEBUGP("jumpshot_transport:  MODE_SENSE_6 detected\n");
-		return jumpshot_handle_mode_sense(us, srb, ptr, TRUE);
+		return jumpshot_handle_mode_sense(us, srb, TRUE);
 	}
 
 	if (srb->cmnd[0] == MODE_SENSE_10) {
 		US_DEBUGP("jumpshot_transport:  MODE_SENSE_10 detected\n");
-		return jumpshot_handle_mode_sense(us, srb, ptr, FALSE);
+		return jumpshot_handle_mode_sense(us, srb, FALSE);
 	}
 
 	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
@@ -615,5 +585,8 @@
 
 	US_DEBUGP("jumpshot_transport:  Gah! Unknown command: %d (0x%x)\n",
 		  srb->cmnd[0], srb->cmnd[0]);
-	return USB_STOR_TRANSPORT_ERROR;
+	info->sense_key = 0x05;
+	info->sense_asc = 0x20;
+	info->sense_ascq = 0x00;
+	return USB_STOR_TRANSPORT_FAILED;
 }
