patch-2.3.12 linux/drivers/usb/usb_scsi.c

Next file: linux/fs/Makefile
Previous file: linux/drivers/usb/usb.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.11/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
@@ -139,10 +139,20 @@
 	this_xfer = length > max_size ? max_size : length;
 	length -= this_xfer;
 	do {
-	    US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);
+	    /*US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);*/
 	    result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, pipe, buf, 
 						    this_xfer, &partial);
 
+	    if (result != 0 || partial != this_xfer)
+		US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n",
+			  result, partial, this_xfer);
+
+	    if (result == USB_ST_STALL) {
+		US_DEBUGP("clearing endpoing halt for pipe %x\n", pipe);
+		usb_clear_halt(us->pusb_dev,
+			       usb_pipeendpoint(pipe) | (pipe & 0x80));
+	    }
+
 	    /* we want to retry if the device reported NAK */
 	    if (result == USB_ST_TIMEOUT) {
 		if (partial != this_xfer) {
@@ -171,28 +181,31 @@
     return 0;
 
 }
+
 static int us_transfer(Scsi_Cmnd *srb, int dir_in)
 {
     struct us_data *us = (struct us_data *)srb->host_scribble;
     int i;
     int result = -1;
+    unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
+	    usb_sndbulkpipe(us->pusb_dev, us->ep_out);
 
     if (srb->use_sg) {
 	struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
 
 	for (i = 0; i < srb->use_sg; i++) {
-	    result = us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
-						  usb_sndbulkpipe(us->pusb_dev, us->ep_out),
-				     sg[i].address, sg[i].length);
+	    result = us_one_transfer(us, pipe, sg[i].address, sg[i].length);
 	    if (result)
 		break;
 	}
-	return result;
     }
     else
-	return us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
-					    usb_sndbulkpipe(us->pusb_dev, us->ep_out),
-			       srb->request_buffer, srb->request_bufflen);
+	result = us_one_transfer(us, pipe,
+				 srb->request_buffer, srb->request_bufflen);
+
+    if (result)
+	US_DEBUGP("us_transfer returning error %d\n", result);
+    return result;
 }
 
 static unsigned int us_transfer_length(Scsi_Cmnd *srb)
@@ -232,12 +245,13 @@
     struct us_data *us = (struct us_data *)dev_id;
 
     if (state != USB_ST_REMOVED) {
-	us->ip_data = *(__u16 *)buffer;
-	US_DEBUGP("Interrupt Status %x\n", us->ip_data);
+	us->ip_data = le16_to_cpup((__u16 *)buffer);
+	/* US_DEBUGP("Interrupt Status %x\n", us->ip_data); */
     }
-    if (us->ip_wanted)
+    if (us->ip_wanted) {
+	us->ip_wanted = 0;
 	wake_up(&us->ip_waitq);
-    us->ip_wanted = 0;
+    }
 
     /* we dont want another interrupt */
 
@@ -250,6 +264,7 @@
     devrequest dr;
     int result;
 
+    US_DEBUGP("pop_CB_reset\n");
     dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE;
     dr.request = US_CBI_ADSC;
     dr.value = 0;
@@ -262,12 +277,15 @@
 					usb_sndctrlpipe(us->pusb_dev,0),
 					&dr, cmd, 12);
 
-    usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
-    usb_clear_halt(us->pusb_dev, us->ep_out);
-
     /* long wait for reset */
 
     schedule_timeout(HZ*5);
+
+    US_DEBUGP("pop_CB_reset: clearing endpoint halt\n");
+    usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
+    usb_clear_halt(us->pusb_dev, us->ep_out);
+
+    US_DEBUGP("pop_CB_reset done\n");
     return 0;
 }
 
@@ -325,6 +343,7 @@
 		/* as per spec try a start command, wait and retry */
 
 		done_start++;
+		memset(cmd, 0, sizeof(cmd));
 		cmd[0] = START_STOP;
 		cmd[4] = 1;		/* start */
 		result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
@@ -338,7 +357,7 @@
 	    result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
 						  usb_sndctrlpipe(us->pusb_dev,0),
 						  &dr, srb->cmnd, srb->cmd_len);
-	if (result != USB_ST_STALL && result != USB_ST_TIMEOUT)
+	if (/*result != USB_ST_STALL &&*/ result != USB_ST_TIMEOUT)
 	    return result;
     }
     return result;
@@ -356,6 +375,7 @@
     devrequest dr;
     int retry = 5;
 
+    US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol);
     switch (us->protocol) {
     case US_PR_CB:
 	/* get from control */
@@ -439,23 +459,26 @@
 	if (result == USB_ST_STALL || result == USB_ST_TIMEOUT)	{
 	    return (DID_OK << 16) | 2;
 	}
-	return DID_ABORT << 16;
+	return DID_ERROR << 16;
     }
 
     /* transfer the data */
 
     if (us_transfer_length(srb)) {
 	result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
-	if (result && result != USB_ST_DATAUNDERRUN) {
+	if (result && result != USB_ST_DATAUNDERRUN && result != USB_ST_STALL) {
 	    US_DEBUGP("CBI  transfer %x\n", result);
-	    return DID_ABORT << 16;
-	} else if (result == USB_ST_DATAUNDERRUN) {
+	    return DID_ERROR << 16;
+	}
+#if 0
+	else if (result == USB_ST_DATAUNDERRUN) {
 	    return DID_OK << 16;
 	}
     } else {
 	if (!result) {
 	    return DID_OK << 16;
 	}
+#endif
     }
 
     /* get status */
@@ -947,6 +970,7 @@
 			    US_DEBUGP("Old/New length = %d/%d\n", savelen, length);
 
 			    if (us->srb->request_bufflen != length) {
+			        US_DEBUGP("redoing cmd with len=%d\n", length);
 				us->srb->request_bufflen = length;
 				us->srb->result = us->pop(us->srb);
 			    }
@@ -957,6 +981,15 @@
 			    case REQUEST_SENSE:
 			    case INQUIRY:
 			    case MODE_SENSE:
+				if (us->srb->use_sg == 0 && length > 0) {
+				    int i;
+				    printk(KERN_DEBUG "Data is");
+				    for (i = 0; i < 32 && i < length; ++i)
+					printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]);
+				    if (i < length)
+					printk(" ...");
+				    printk("\n");
+				}
 				us->srb->cmnd[4] = saveallocation;
 				break;
 
@@ -969,6 +1002,7 @@
 			}
 			/* force attention on first command */
 			if (!us->attention_done) {
+			    US_DEBUGP("forcing unit attention\n");
 			    if (us->srb->cmnd[0] == REQUEST_SENSE) {
 				if (us->srb->result == (DID_OK << 16)) {
 				    unsigned char *p = (unsigned char *)us->srb->request_buffer;
@@ -987,6 +1021,7 @@
 			}
 		    }
 		}
+		US_DEBUGP("scsi cmd done, result=%x\n", us->srb->result);
 		us->srb->scsi_done(us->srb);
 		us->srb = NULL;
 		break;

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