Skip to contentSkip to conversation

Handling erroneous READ CAPACITY response in sd.c

DISCUSSION Alan Stern 2 participants 3 messages Oct 27, 2004 – Oct 29, 2004 1 message not in the archive

Subsystems (3)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Alan Stern

author maintainer
#1 lore raw
Quoted 6 lines · Darsen

I applied this patch but failed in many places.
neither kernel 2.6.8.1 nor 2.6.9 works.

Could you tell me what version it should be applied on?

Thanks

Sorry, that patch was meant for 2.6.10-rc1 (and a development version, not the standard version at that). Below is the equivalent patch for vanilla 2.6.9. Thanks for testing it.

Alan Stern

drivers/scsi/sd.c +10 -0
diff -ur linux-2.6.9/drivers/scsi/sd.c linux-2.6.9-new/drivers/scsi/sd.c
@@ -1129,6 +1129,16 @@
 		 */
 		sdkp->capacity = 0;
 	}
+
+	/* Handle broken devices that return the total number of sectors
+	 * rather than the highest sector number, by forcing the total
+	 * number to be even. */
+	if (sdp->even_capacity && (sdkp->capacity & 1)) {
+		printk(KERN_NOTICE "%s : odd number of sectors reported, "
+			"decreasing by one.\n", diskname);
+		--sdkp->capacity;
+	}
+
 	{
 		/*
 		 * The msdos fs needs to know the hardware sector size
drivers/usb/storage/protocol.c +0 -33
diff -ur linux-2.6.9/drivers/usb/storage/protocol.c linux-2.6.9-new/drivers/usb/storage/protocol.c
@@ -89,35 +89,6 @@
 			&index, &offset, TO_XFER_BUF);
 }
 
-/*
- * Fix-up the return data from a READ CAPACITY command. My Feiya reader
- * returns a value that is 1 too large.
- */
-static void fix_read_capacity(struct scsi_cmnd *srb)
-{
-	unsigned int index, offset;
-	__be32 c;
-	unsigned long capacity;
-
-	/* verify that it's a READ CAPACITY command */
-	if (srb->cmnd[0] != READ_CAPACITY)
-		return;
-
-	index = offset = 0;
-	if (usb_stor_access_xfer_buf((unsigned char *) &c, 4, srb,
-			&index, &offset, FROM_XFER_BUF) != 4)
-		return;
-
-	capacity = be32_to_cpu(c);
-	US_DEBUGP("US: Fixing capacity: from %ld to %ld\n",
-	       capacity+1, capacity);
-	c = cpu_to_be32(capacity - 1);
-
-	index = offset = 0;
-	usb_stor_access_xfer_buf((unsigned char *) &c, 4, srb,
-			&index, &offset, TO_XFER_BUF);
-}
-
 /***********************************************************************
  * Protocol routines
  ***********************************************************************/
@@ -224,10 +195,6 @@
 	if (srb->result == SAM_STAT_GOOD) {
 		/* Fix the INQUIRY data if necessary */
 		fix_inquiry_data(srb);
-
-		/* Fix the READ CAPACITY result if necessary */
-		if (us->flags & US_FL_FIX_CAPACITY)
-			fix_read_capacity(srb);
 	}
 }
 
drivers/usb/storage/scsiglue.c +6 -1
diff -ur linux-2.6.9/drivers/usb/storage/scsiglue.c linux-2.6.9-new/drivers/usb/storage/scsiglue.c
@@ -135,6 +135,12 @@
 		sdev->skip_ms_page_3f = 1;
 #endif
 
+		/* Some devices return the total number of blocks in
+		 * response to READ CAPACITY instead of the highest
+		 * block number.  Deal with this by forcing the number
+		 * of blocks to be even.  Fortunately no existing USB
+		 * drive has an odd number of blocks, so far as I know! */
+		sdev->even_capacity = 1;
 	} else {
 
 		/* Non-disk-type devices don't need to blacklist any pages
@@ -358,7 +364,6 @@
 		DO_FLAG(SINGLE_LUN);
 		DO_FLAG(SCM_MULT_TARG);
 		DO_FLAG(FIX_INQUIRY);
-		DO_FLAG(FIX_CAPACITY);
 
 		*(pos++) = '\n';
 	}
drivers/usb/storage/unusual_devs.h +0 -14
diff -ur linux-2.6.9/drivers/usb/storage/unusual_devs.h linux-2.6.9-new/drivers/usb/storage/unusual_devs.h
@@ -490,13 +490,6 @@
 		US_FL_SINGLE_LUN ),
 #endif
 
-/* Reported by Darsen Lu <[email protected]> */
-UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001,
-		"SigmaTel",
-		"USBMSC Audio Player",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_CAPACITY ),
-
 /* Submitted by Benny Sjostrand <[email protected]> */
 UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
 		"Minolta",
@@ -711,13 +704,6 @@
 		US_SC_RBC, US_PR_BULK, NULL,
 		US_FL_MODE_XLATE),
 
-/* aeb */
-UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
-		"Feiya",
-		"5-in-1 Card Reader",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_CAPACITY ),
-
 UNUSUAL_DEV(  0x097a, 0x0001, 0x0000, 0x0001,
 		"Minds@Work",
 		"Digital Wallet",
drivers/usb/storage/usb.h +1 -1
diff -ur linux-2.6.9/drivers/usb/storage/usb.h linux-2.6.9-new/drivers/usb/storage/usb.h
@@ -72,7 +72,7 @@
 #define US_FL_IGNORE_SER      0		 /* [no longer used]		    */
 #define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets	    */
 #define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs faking   */
-#define US_FL_FIX_CAPACITY    0x00000080 /* READ CAPACITY response too big  */
+#define US_FL_FIX_CAPACITY    0		 /* [no longer used]		    */
 
 /* Dynamic flag definitions: used in set_bit() etc. */
 #define US_FLIDX_URB_ACTIVE	18  /* 0x00040000  current_urb is in use  */
include/scsi/scsi_device.h +1 -0
diff -ur linux-2.6.9/include/scsi/scsi_device.h linux-2.6.9-new/include/scsi/scsi_device.h
@@ -106,6 +106,7 @@
 	unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
 	unsigned no_start_on_add:1;	/* do not issue start on add */
 	unsigned allow_restart:1; /* issue START_UNIT in error handler */
+	unsigned even_capacity:1; /* must have an even number of sectors */
 
 	unsigned int device_blocked;	/* Device returned QUEUE_FULL. */
 
#2 lore raw

I tested the patch on 2.6.9 and everything works fine.
There are some error messages, but I believe they already existed before the patch was applied :)

-------------<dmsg part 1>-----------

usb-storage: usb_stor_bulk_transfer_buf: xfer 13 bytes
usb-storage: Status code 0; transferred 13/13
usb-storage: -- transfer complete
usb-storage: Bulk status result = 0
usb-storage: Bulk Status S 0x53425355 T 0x12f R 0 Stat 0x0
usb-storage: scsi cmd done, result=0x0
usb-storage: *** thread sleeping.
sda : odd number of sectors reported, decreasing by one. SCSI device sda: 251904 512-byte hdwr sectors (129 MB)
sda: assuming Write Enabled
sda: assuming drive cache: write through
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Command TEST_UNIT_READY (6 bytes)

---------------<dmsg part 2>--------------

Attached scsi removable disk sda at scsi1, channel 0, id 0, lun 0 Attached scsi generic sg0 at scsi1, channel 0, id 0, lun 0, type 0
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Bad LUN (0:1)
usb-storage: scsi cmd done, result=0x40000
usb-storage: *** thread sleeping.
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Bad target number (1:0)
usb-storage: scsi cmd done, result=0x40000
usb-storage: *** thread sleeping.
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Bad target number (2:0)
usb-storage: scsi cmd done, result=0x40000
usb-storage: *** thread sleeping.
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Bad target number (3:0)
usb-storage: scsi cmd done, result=0x40000
usb-storage: *** thread sleeping.
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Bad target number (4:0)
usb-storage: scsi cmd done, result=0x40000
usb-storage: *** thread sleeping.
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Bad target number (5:0)
usb-storage: scsi cmd done, result=0x40000
usb-storage: *** thread sleeping.
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Bad target number (6:0)
usb-storage: scsi cmd done, result=0x40000
usb-storage: *** thread sleeping.
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Bad target number (7:0)
usb-storage: scsi cmd done, result=0x40000
usb-storage: *** thread sleeping.
USB Mass Storage device found at 4

(end of log)

Quoted 30 lines · Alan Stern
Quoted 8 lines · Darsen

I applied this patch but failed in many places.
neither kernel 2.6.8.1 nor 2.6.9 works.

Could you tell me what version it should be applied on?

Thanks

Sorry, that patch was meant for 2.6.10-rc1 (and a development version, not the standard version at that). Below is the equivalent patch for vanilla 2.6.9. Thanks for testing it.

Alan Stern

diff -ur linux-2.6.9/drivers/scsi/sd.c linux-2.6.9-new/drivers/scsi/sd.c

drivers/scsi/sd.c +2 -0
@@ -1129,6 +1129,16 @@
 		 */
 		sdkp->capacity = 0;
 	}
+
+	/* Handle broken devices that return the total number of sectors
 
 
author maintainer
#3 lore raw
Quoted 6 lines · Darsen

I tested the patch on 2.6.9 and everything works fine.
There are some error messages, but I believe they already existed before the patch was applied :)

-------------<dmsg part 1>-----------

Quoted 14 lines

usb-storage: usb_stor_bulk_transfer_buf: xfer 13 bytes
usb-storage: Status code 0; transferred 13/13
usb-storage: -- transfer complete
usb-storage: Bulk status result = 0
usb-storage: Bulk Status S 0x53425355 T 0x12f R 0 Stat 0x0
usb-storage: scsi cmd done, result=0x0
usb-storage: *** thread sleeping.
sda : odd number of sectors reported, decreasing by one. SCSI device sda: 251904 512-byte hdwr sectors (129 MB)
sda: assuming Write Enabled
sda: assuming drive cache: write through
usb-storage: queuecommand called
usb-storage: *** thread awakened.
usb-storage: Command TEST_UNIT_READY (6 bytes)

This looks very good. Thanks for doing the test.

And yes, those other error messages are completely normal.

Alan Stern