Hi everyone, Short: Attached is an incomplete patch that allows user space to force the capacity of an scsi device to a specific value. Any not over my-dead-body objections with that? Long: I was unfortunate and grabbed one of the cheaper USB SD card readers that do not correctly detect >1GB capacity sd cards. This is a known and common bug. See [1] or [2]. What's interesting is that this card reader was sold to work with these cards explicitly, and I figured it must have been tested only under Windows, which we all know believes in the partition table more strongly than in what the device reports. And indeed, my 2GB sd cards start to work if I simply ignore the capacity reported by the device. I have been using this successfully in the last half year with all my sd cards and now I'm tired of patching the kernel for just that thing. Could you imagine to merge that upstream? I doubt that any device will kill itself if this interface is used incorrectly. A simple user space program using the new interface is available at [3]. Please CC, me not on list. [1] http://en.wikipedia.org/wiki/Secure_Digital#Standard-SD_cards_.28non-SDHC.29_with_greater_than_1_GB_capacity [2] http://www.hjreggel.net/cardspeed/special-sd.html [3] http://blog.clemens.endorphin.org/2009/03/patching-for-broken-sd-card-readers.html -- Fruhwirth Clemens http://clemens.endorphin.org
diff -ru linux-2.6.28/drivers/scsi/sd.c linux-2.6.28/drivers/scsi/sd.c --- linux-2.6.28/drivers/scsi/sd.c 2009-03-21 13:36:48.000000000 +0100 +++ linux-2.6.28/drivers/scsi/sd.c 2009-03-21 13:07:43.000000000 +0100 @@ -725,6 +725,19 @@ return 0; } +static int scsi_ioctl_set_capacity(struct scsi_disk *sdkp, void __user *arg) +{ + int val, result; + + result = get_user(val, (int __user *)arg); + if (result) + return result; + sdkp->capacity = val; + set_capacity(sdkp->disk, sdkp->capacity); + + return 0; +} + /** * sd_ioctl - process an ioctl * @inode: only i_rdev/i_bdev members may be used @@ -770,6 +786,11 @@ case SCSI_IOCTL_GET_IDLUN: case SCSI_IOCTL_GET_BUS_NUMBER: return scsi_ioctl(sdp, cmd, p); + case SCSI_IOCTL_SET_CAPACITY: + return scsi_ioctl_set_capacity(scsi_disk(disk), (int __user *)arg); + case SCSI_IOCTL_GET_CAPACITY: + return put_user(scsi_disk(disk)->capacity, (int __user *)arg); + default: error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p); if (error != -ENOTTY) diff -ru linux-2.6.28/include/scsi/scsi_ioctl.h linux-2.6.28/include/scsi/scsi_ioctl.h --- linux-2.6.28/include/scsi/scsi_ioctl.h 2008-12-25 00:26:37.000000000 +0100 +++ linux-2.6.28/include/scsi/scsi_ioctl.h 2009-03-21 12:48:45.000000000 +0100 @@ -11,6 +11,8 @@ the cdrom */ #define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */ #define SCSI_IOCTL_DOORUNLOCK 0x5381 /* unlock the mechanism */ +#define SCSI_IOCTL_SET_CAPACITY 0x5388 /* set capacity */ +#define SCSI_IOCTL_GET_CAPACITY 0x5389 /* get capacity */ #define SCSI_REMOVAL_PREVENT 1 #define SCSI_REMOVAL_ALLOW 0