All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] sd: fixup capacity calculation for 4k drives
@ 2016-03-29  8:06 Hannes Reinecke
  2016-04-10  2:02 ` Lee Duncan
  0 siblings, 1 reply; 9+ messages in thread
From: Hannes Reinecke @ 2016-03-29  8:06 UTC (permalink / raw)
  To: Martin K. Petersen
  Cc: Christoph Hellwig, James Bottomley, Bart van Assche,
	Ewan D. Milne, linux-scsi, Hannes Reinecke

in sd_read_capacity() the sdkp->capacity field changes its meaning:
after the call to read_capacity_XX() it carries the _unscaled_ values,
making the comparison between the original value and the new value
always false for drives with a sector size != 512.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 drivers/scsi/sd.c | 69 +++++++++++++++++++++++++++++++------------------------
 1 file changed, 39 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5a5457a..0afe113 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2046,7 +2046,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
 #define READ_CAPACITY_RETRIES_ON_RESET	10
 
 static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
-						unsigned char *buffer)
+			    unsigned char *buffer, u64 *capacity)
 {
 	unsigned char cmd[16];
 	struct scsi_sense_hdr sshdr;
@@ -2054,8 +2054,8 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
 	int the_result;
 	int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
 	unsigned int alignment;
-	unsigned long long lba;
-	unsigned sector_size;
+	u64 lba;
+	u32 sector_size;
 
 	if (sdp->no_read_capacity_16)
 		return -EINVAL;
@@ -2114,7 +2114,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
 		sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
 			"kernel compiled with support for large block "
 			"devices.\n");
-		sdkp->capacity = 0;
+		*capacity = 0;
 		return -EOVERFLOW;
 	}
 
@@ -2137,20 +2137,20 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
 		sd_config_discard(sdkp, SD_LBP_WS16);
 	}
 
-	sdkp->capacity = lba + 1;
+	*capacity = lba + 1;
 	return sector_size;
 }
 
 static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
-						unsigned char *buffer)
+			    unsigned char *buffer, u64 *capacity)
 {
 	unsigned char cmd[16];
 	struct scsi_sense_hdr sshdr;
 	int sense_valid = 0;
 	int the_result;
 	int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
-	sector_t lba;
-	unsigned sector_size;
+	u32 lba;
+	u32 sector_size;
 
 	do {
 		cmd[0] = READ_CAPACITY;
@@ -2191,7 +2191,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
 		/* Some buggy (usb cardreader) devices return an lba of
 		   0xffffffff when the want to report a size of 0 (with
 		   which they really mean no media is present) */
-		sdkp->capacity = 0;
+		*capacity = 0;
 		sdkp->physical_block_size = sector_size;
 		return sector_size;
 	}
@@ -2200,11 +2200,11 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
 		sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
 			"kernel compiled with support for large block "
 			"devices.\n");
-		sdkp->capacity = 0;
+		*capacity = 0;
 		return -EOVERFLOW;
 	}
 
-	sdkp->capacity = lba + 1;
+	*capacity = (u64)lba + 1;
 	sdkp->physical_block_size = sector_size;
 	return sector_size;
 }
@@ -2230,34 +2230,38 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
 {
 	int sector_size;
 	struct scsi_device *sdp = sdkp->device;
-	sector_t old_capacity = sdkp->capacity;
+	u64 old_capacity = sdkp->capacity, new_capacity;
 
 	if (sd_try_rc16_first(sdp)) {
-		sector_size = read_capacity_16(sdkp, sdp, buffer);
+		sector_size = read_capacity_16(sdkp, sdp, buffer,
+					       &new_capacity);
 		if (sector_size == -EOVERFLOW)
 			goto got_data;
 		if (sector_size == -ENODEV)
 			return;
 		if (sector_size < 0)
-			sector_size = read_capacity_10(sdkp, sdp, buffer);
+			sector_size = read_capacity_10(sdkp, sdp, buffer,
+						       &new_capacity);
 		if (sector_size < 0)
 			return;
 	} else {
-		sector_size = read_capacity_10(sdkp, sdp, buffer);
+		sector_size = read_capacity_10(sdkp, sdp, buffer,
+					       &new_capacity);
 		if (sector_size == -EOVERFLOW)
 			goto got_data;
 		if (sector_size < 0)
 			return;
 		if ((sizeof(sdkp->capacity) > 4) &&
-		    (sdkp->capacity > 0xffffffffULL)) {
+		    (new_capacity > 0xffffffffULL)) {
 			int old_sector_size = sector_size;
 			sd_printk(KERN_NOTICE, sdkp, "Very big device. "
 					"Trying to use READ CAPACITY(16).\n");
-			sector_size = read_capacity_16(sdkp, sdp, buffer);
+			sector_size = read_capacity_16(sdkp, sdp, buffer,
+						       &new_capacity);
 			if (sector_size < 0) {
 				sd_printk(KERN_NOTICE, sdkp,
 					"Using 0xffffffff as device size\n");
-				sdkp->capacity = 1 + (sector_t) 0xffffffff;
+				new_capacity = 1 + (u64) 0xffffffff;
 				sector_size = old_sector_size;
 				goto got_data;
 			}
@@ -2275,11 +2279,11 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
 	 * the capacity.
 	 */
 	if (sdp->fix_capacity ||
-	    (sdp->guess_capacity && (sdkp->capacity & 0x01))) {
+	    (sdp->guess_capacity && (new_capacity & 0x01))) {
 		sd_printk(KERN_INFO, sdkp, "Adjusting the sector count "
 				"from its reported value: %llu\n",
-				(unsigned long long) sdkp->capacity);
-		--sdkp->capacity;
+				(unsigned long long) new_capacity);
+		--new_capacity;
 	}
 
 got_data:
@@ -2301,7 +2305,7 @@ got_data:
 		 * would be relatively trivial to set the thing up.
 		 * For this reason, we leave the thing in the table.
 		 */
-		sdkp->capacity = 0;
+		new_capacity = 0;
 		/*
 		 * set a bogus sector size so the normal read/write
 		 * logic in the block layer will eventually refuse any
@@ -2312,6 +2316,19 @@ got_data:
 	}
 	blk_queue_logical_block_size(sdp->request_queue, sector_size);
 
+	/*
+	 * Note: up to this point new_capacity carries the
+	 * _unscaled_ capacity. So rescale capacity to 512-byte units.
+	 */
+	if (sector_size == 4096)
+		sdkp->capacity = new_capacity << 3;
+	else if (sector_size == 2048)
+		sdkp->capacity = new_capacity << 2;
+	else if (sector_size == 1024)
+		sdkp->capacity = new_capacity << 1;
+	else
+		sdkp->capacity = new_capacity;
+
 	{
 		char cap_str_2[10], cap_str_10[10];
 
@@ -2337,14 +2354,6 @@ got_data:
 	if (sdkp->capacity > 0xffffffff)
 		sdp->use_16_for_rw = 1;
 
-	/* Rescale capacity to 512-byte units */
-	if (sector_size == 4096)
-		sdkp->capacity <<= 3;
-	else if (sector_size == 2048)
-		sdkp->capacity <<= 2;
-	else if (sector_size == 1024)
-		sdkp->capacity <<= 1;
-
 	blk_queue_physical_block_size(sdp->request_queue,
 				      sdkp->physical_block_size);
 	sdkp->device->sector_size = sector_size;
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 9+ messages in thread
* [PATCH] sd: fixup capacity calculation for 4k drives
@ 2016-03-21 12:27 Hannes Reinecke
  2016-03-21 14:31 ` Christoph Hellwig
  2016-03-22  1:16 ` Martin K. Petersen
  0 siblings, 2 replies; 9+ messages in thread
From: Hannes Reinecke @ 2016-03-21 12:27 UTC (permalink / raw)
  To: Martin K. Petersen
  Cc: Christoph Hellwig, James Bottomley, linux-scsi, Hannes Reinecke

in sd_read_capacity() the sdkp->capacity field changes its meaning:
after the call to read_capacity_XX() it carries the _unscaled_ values,
making the comparison between the original value and the new value
always false for drives with a sector size != 512.
So introduce a 'new_capacity' carrying the new, scaled, capacity.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 drivers/scsi/sd.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5a5457a..fbb8daa 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2312,8 +2312,13 @@ got_data:
 	}
 	blk_queue_logical_block_size(sdp->request_queue, sector_size);
 
+	/*
+	 * Note: up to this point sdkp->capacity carries the
+	 * _unscaled_ capacity (cf the scaling after this block).
+	 */
 	{
 		char cap_str_2[10], cap_str_10[10];
+		size_t new_capacity = sdkp->capacity >> (ilog2(sector_size) - 9);
 
 		string_get_size(sdkp->capacity, sector_size,
 				STRING_UNITS_2, cap_str_2, sizeof(cap_str_2));
@@ -2321,7 +2326,7 @@ got_data:
 				STRING_UNITS_10, cap_str_10,
 				sizeof(cap_str_10));
 
-		if (sdkp->first_scan || old_capacity != sdkp->capacity) {
+		if (sdkp->first_scan || old_capacity != new_capacity) {
 			sd_printk(KERN_NOTICE, sdkp,
 				  "%llu %d-byte logical blocks: (%s/%s)\n",
 				  (unsigned long long)sdkp->capacity,
-- 
1.8.5.6


^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-04-10  2:06 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-29  8:06 [PATCH] sd: fixup capacity calculation for 4k drives Hannes Reinecke
2016-04-10  2:02 ` Lee Duncan
  -- strict thread matches above, loose matches on Subject: below --
2016-03-21 12:27 Hannes Reinecke
2016-03-21 14:31 ` Christoph Hellwig
2016-03-22  1:16 ` Martin K. Petersen
2016-03-22  6:55   ` Christoph Hellwig
2016-03-22  7:14   ` Hannes Reinecke
2016-03-22 14:16     ` Ewan D. Milne
2016-03-29  1:14       ` Martin K. Petersen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.