Harddrive with 4096 physical sector size reported as 512 behind USB bridge

block-devicehard-diskusb-drive

I bought a new (in 2017) 4 TB harddrive, so I expected it to have a 4096 physical sector size. Indeed,

$ hdparm -I /dev/sdh
  ...
  Logical  Sector size:                   512 bytes
  Physical Sector size:                  4096 bytes
  Logical Sector-0 offset:                  0 bytes
  device size with M = 1000*1000:     4000787 MBytes (4000 GB)

However, when I tried to partition it with parted, I got a physical block size of 512:

$ parted /dev/sdh print
Model:   (scsi)
Disk /dev/sdh: 4001GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

The drive is on an USB 3 port in a dockingstation (iTec) behind a USB bridge (152d:0561, JMicron JMS55 chipset).

The block layer seems to have the wrong size, too:

$ cat /sys/block/sdh/queue/physical_block_size
512
$ cat /sys/block/sdh/queue/minimum_io_size 
512

An READ CAPACITY (16) SCSI commands reports the wrong size, too:

$ sudo sg_readcap --16 /dev/sdh
Read Capacity results:
  Protection: prot_en=0, p_type=0, p_i_exponent=0
  Logical block provisioning: lbpme=0, lbprz=0
  Last logical block address=7814037167 (0x1d1c0beaf),
  Number of logical blocks=7814037168
  Logical block length=512 bytes
  Logical blocks per physical block exponent=0
  Lowest aligned logical block address=0

instead of (from another drive)

  Logical blocks per physical block exponent=3 [so physical block length=4096 bytes]

On the other hand, blockdev reports

$ blockdev --report /dev/sdh
RO    RA   SSZ   BSZ   StartSec            Size   Device
rw   256   512  4096          0   4000787030016   /dev/sdh

Googling finds vague information about USB bridges that do "4k/512 sector emulation, to allow large harddisks to have a MBR partition table", but if I understand this correctly, then the logical sector size should be 4096 for these bridges, which is not the case for my bridge.

So what exactly is going on? And how can I fix it, i.e. convince the kernel that this drive has physical blocks of 4096 bytes size? The physical_block_size and minimum_io_size attributes are not writeable.

One possible explanation is that there's a bug in the firmware of the bridge, and it just copies the first 12 bytes of the READ CAPACITY (16) response, zeroing out the exponent in byte 13. But in that case, I'd still like to work around the bug somehow.


Edit

I now tested it in a different (older) USB enclosure. Connecting with eSATA, everything works as intended, and READ CAPACITY (16) reports 4096 bytes physical sector size. Connecting via USB (04fc:0c25 Sunplus SATALink SPIF225A) complains that READ CAPACITY (16) is not supported (so no physical sector size), but READ CAPACITY (10) is.

That confirms that at least for the Sunplus bridge, SCSI commands are not arbitrarily forwarded, and makes it seem more likely that the JMicron USB bridge has a bug in the firmware, zeroing out the READ CAPACITY (16) response.

But I still need to know how to work around that bug.

Best Answer

man blockdev

   --setbsz bytes
          Set blocksize. Note that the block size is specific to the  cur‐
          rent  file descriptor opening the block device, so the change of
          block size only persists for as long as blockdev has the  device
          open, and is lost once blockdev exits.

In block/ioctl.c:

case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
    return put_int(arg, block_size(bdev));
case BLKSSZGET: /* get block device logical block size */
    return put_int(arg, bdev_logical_block_size(bdev));
case BLKPBSZGET: /* get block device physical block size */
    return put_uint(arg, bdev_physical_block_size(bdev));

So BSZ reported by blockdev is neither logical nor physical block size. It is the "soft block size".

Looking at this code, the part about soft block size being specific to the file descriptor does not appear to make sense. Nor does wanting to set that with blockdev, given that no other option is documented in terms of blocks (only fixed-size 512 byte sectors).

In my own tests, what actually happens is that BSZ is preserved for as long as any process holds the block device open. It looks like it gets reset on the last close().

Parted got confused by this too some years ago

belay that. BLKBSZGET is the kernel's chosen block size it will use to access the device (for normal disks turns out this is 1k, for ata_ram this is 4k), which is not the underlying disk's logical block size. :-( So we will likely need another ioctl() to get the right value from the kernel, and BLKSSZGET may wind up being the disks's logical block size, while a new ioctl() exports the disk's physical sector size. ugh.

Another quirk:

On Wed, Apr 09, 2003 at 06:53:17PM +0200, Rob van Nieuwkerk wrote:

I get 4096 with BLKBSZGET on several unmounted partitions on my system (RH 2.4.18-27.7.x kernel). Some give 1024 .. Maybe it is because I had them mounted first and unmounted them for the test ?

That would be the most likely answer. When you unmount, I don't believe the filesystem bothers to set_blocksize(get_hardsect_size(dev)).

Related Question