ChangeSet 1.1508.1.5, 2003/06/30 10:59:06-07:00, mdharm-usb@one-eyed-alien.net

[PATCH] USB storage: create private I/O buffer

This patch creates a private I/O buffer for the 'core' subdrivers.  This
allows us to fix all cases of DMAing to/from the stacks, statics, or other
bad places.


 drivers/usb/storage/transport.c |   83 ++++++++++++++++++++--------------------
 drivers/usb/storage/usb.c       |   14 ++++--
 drivers/usb/storage/usb.h       |    6 +-
 3 files changed, 55 insertions(+), 48 deletions(-)


diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Tue Jul  1 14:24:13 2003
+++ b/drivers/usb/storage/transport.c	Tue Jul  1 14:24:13 2003
@@ -786,9 +786,9 @@
 	}
 
 	/* STATUS STAGE */
-	result = usb_stor_intr_transfer(us, us->irqdata, sizeof(us->irqdata));
+	result = usb_stor_intr_transfer(us, us->iobuf, 2);
 	US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", 
-			us->irqdata[0], us->irqdata[1]);
+			us->iobuf[0], us->iobuf[1]);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
@@ -804,7 +804,7 @@
 		    srb->cmnd[0] == INQUIRY)
 			return USB_STOR_TRANSPORT_GOOD;
 		else {
-			if (us->irqdata[0])
+			if (us->iobuf[0])
 				return USB_STOR_TRANSPORT_FAILED;
 			else
 				return USB_STOR_TRANSPORT_GOOD;
@@ -815,13 +815,13 @@
 	 * The first byte should always be a 0x0
 	 * The second byte & 0x0F should be 0x0 for good, otherwise error 
 	 */
-	if (us->irqdata[0]) {
+	if (us->iobuf[0]) {
 		US_DEBUGP("CBI IRQ data showed reserved bType %d\n",
-				us->irqdata[0]);
+				us->iobuf[0]);
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
-	switch (us->irqdata[1] & 0x0F) {
+	switch (us->iobuf[1] & 0x0F) {
 		case 0x00: 
 			return USB_STOR_TRANSPORT_GOOD;
 		case 0x01: 
@@ -889,7 +889,6 @@
 /* Determine what the maximum LUN supported is */
 int usb_stor_Bulk_max_lun(struct us_data *us)
 {
-	unsigned char data;
 	int result;
 
 	/* issue the command */
@@ -897,14 +896,14 @@
 				 US_BULK_GET_MAX_LUN, 
 				 USB_DIR_IN | USB_TYPE_CLASS | 
 				 USB_RECIP_INTERFACE,
-				 0, us->ifnum, &data, sizeof(data), HZ);
+				 0, us->ifnum, us->iobuf, 1, HZ);
 
 	US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
-		  result, data);
+		  result, us->iobuf[0]);
 
 	/* if we have a successful request, return the result */
 	if (result == 1)
-		return data;
+		return us->iobuf[0];
 
 	/* return the default -- no LUNs */
 	return 0;
@@ -912,33 +911,34 @@
 
 int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
-	struct bulk_cb_wrap bcb;
-	struct bulk_cs_wrap bcs;
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
 	unsigned int transfer_length = srb->request_bufflen;
 	int result;
 	int fake_sense = 0;
 
 	/* set up the command wrapper */
-	bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
-	bcb.DataTransferLength = cpu_to_le32(transfer_length);
-	bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
-	bcb.Tag = srb->serial_number;
-	bcb.Lun = srb->device->lun;
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = cpu_to_le32(transfer_length);
+	bcb->Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
+	bcb->Tag = srb->serial_number;
+	bcb->Lun = srb->device->lun;
 	if (us->flags & US_FL_SCM_MULT_TARG)
-		bcb.Lun |= srb->device->id << 4;
-	bcb.Length = srb->cmd_len;
+		bcb->Lun |= srb->device->id << 4;
+	bcb->Length = srb->cmd_len;
 
 	/* copy the command payload */
-	memset(bcb.CDB, 0, sizeof(bcb.CDB));
-	memcpy(bcb.CDB, srb->cmnd, bcb.Length);
+	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);
+			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_transfer_buf(us, us->send_bulk_pipe,
-				&bcb, US_BULK_CB_WRAP_LEN, NULL);
+				bcb, US_BULK_CB_WRAP_LEN, NULL);
 	US_DEBUGP("Bulk command transfer result=%d\n", result);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
@@ -972,7 +972,7 @@
 	/* get CSW for device status */
 	US_DEBUGP("Attempting to get CSW...\n");
 	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
-				&bcs, US_BULK_CS_WRAP_LEN, NULL);
+				bcs, US_BULK_CS_WRAP_LEN, NULL);
 
 	/* did the attempt to read the CSW fail? */
 	if (result == USB_STOR_XFER_STALLED) {
@@ -980,7 +980,7 @@
 		/* get the status again */
 		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
 		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
-				&bcs, US_BULK_CS_WRAP_LEN, NULL);
+				bcs, US_BULK_CS_WRAP_LEN, NULL);
 	}
 
 	/* if we still have a failure at this point, we're in trouble */
@@ -990,17 +990,18 @@
 
 	/* 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) {
+			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 != srb->serial_number || 
+			bcs->Status > US_BULK_STAT_PHASE) {
 		US_DEBUGP("Bulk logical error\n");
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
 	/* based on the status code, we report good or bad */
-	switch (bcs.Status) {
+	switch (bcs->Status) {
 		case US_BULK_STAT_OK:
 			/* device babbled -- return fake sense data */
 			if (fake_sense) {
@@ -1087,18 +1088,18 @@
 
 /* This issues a CB[I] Reset to the device in question
  */
+#define CB_RESET_CMD_SIZE	12
+
 int usb_stor_CB_reset(struct us_data *us)
 {
-	unsigned char cmd[12];
-
-	US_DEBUGP("CB_reset() called\n");
+	US_DEBUGP("%s called\n", __FUNCTION__);
 
-	memset(cmd, 0xFF, sizeof(cmd));
-	cmd[0] = SEND_DIAGNOSTIC;
-	cmd[1] = 4;
+	memset(us->iobuf, 0xFF, CB_RESET_CMD_SIZE);
+	us->iobuf[0] = SEND_DIAGNOSTIC;
+	us->iobuf[1] = 4;
 	return usb_stor_reset_common(us, US_CBI_ADSC, 
 				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-				 0, us->ifnum, cmd, sizeof(cmd));
+				 0, us->ifnum, us->iobuf, CB_RESET_CMD_SIZE);
 }
 
 /* This issues a Bulk-only Reset to the device in question, including
@@ -1106,7 +1107,7 @@
  */
 int usb_stor_Bulk_reset(struct us_data *us)
 {
-	US_DEBUGP("Bulk reset requested\n");
+	US_DEBUGP("%s called\n", __FUNCTION__);
 
 	return usb_stor_reset_common(us, US_BULK_RESET_REQUEST, 
 				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Tue Jul  1 14:24:13 2003
+++ b/drivers/usb/storage/usb.c	Tue Jul  1 14:24:13 2003
@@ -743,17 +743,21 @@
 	int p;
 
 	/* Allocate the USB control blocks */
-	US_DEBUGP("Allocating usb_ctrlrequest\n");
 	us->dr = kmalloc(sizeof(*us->dr), GFP_KERNEL);
 	if (!us->dr) {
-		US_DEBUGP("allocation failed\n");
+		US_DEBUGP("usb_ctrlrequest allocation failed\n");
 		return -ENOMEM;
 	}
 
-	US_DEBUGP("Allocating URB\n");
 	us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!us->current_urb) {
-		US_DEBUGP("allocation failed\n");
+		US_DEBUGP("URB allocation failed\n");
+		return -ENOMEM;
+	}
+
+	us->iobuf = kmalloc(US_IOBUF_SIZE, GFP_KERNEL);
+	if (!us->iobuf) {
+		US_DEBUGP("I/O buffer allocation failed\n");
 		return -ENOMEM;
 	}
 
@@ -852,6 +856,8 @@
 	}
 
 	/* Free the USB control blocks */
+	if (us->iobuf)
+		kfree(us->iobuf);
 	if (us->current_urb)
 		usb_free_urb(us->current_urb);
 	if (us->dr)
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h	Tue Jul  1 14:24:13 2003
+++ b/drivers/usb/storage/usb.h	Tue Jul  1 14:24:13 2003
@@ -92,6 +92,8 @@
 
 #define USB_STOR_STRING_LEN 32
 
+#define US_IOBUF_SIZE		32	/* Big enough for bulk-only CBW */
+
 typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
 typedef int (*trans_reset)(struct us_data*);
 typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
@@ -139,13 +141,11 @@
 	int			pid;		 /* control thread	 */
 	int			sm_state;	 /* what we are doing	 */
 
-	/* interrupt communications data */
-	unsigned char		irqdata[2];	 /* data from USB IRQ	 */
-
 	/* control and bulk communications data */
 	struct urb		*current_urb;	 /* non-int USB requests */
 	struct usb_ctrlrequest	*dr;		 /* control requests	 */
 	struct usb_sg_request	current_sg;	 /* scatter-gather USB   */
+	unsigned char		*iobuf;		 /* I/O buffer		 */
 
 	/* the semaphore for sleeping the control thread */
 	struct semaphore	sema;		 /* to sleep thread on   */
