Skip to content

Instantly share code, notes, and snippets.

@cathay4t
Last active November 2, 2023 06:47
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cathay4t/e80e02a737242a5f3824606543631bfe to your computer and use it in GitHub Desktop.
Save cathay4t/e80e02a737242a5f3824606543631bfe to your computer and use it in GitHub Desktop.
Notes for Linux SCSI logical block provisioning

Logical block provisioning - SBC

Each LBA has one of these three LBP(logical block provisioning) states:

  • LBP1: Mapped.
  • LBP2: Deallocated. (unmapped)
  • LBP3: Anchored. (unmapped)

The LBP2: Deallocated is mandatory for thin provisioned logical unit.

The deallocated means neither the mapping resource nor LBA to physical block(s) relationship is allocated.

The anchored means the LBA mapping resources is associated while LBA to physical block(s) relationship is uncertain.

There are two provisioning type:

  • Resource provisioned: PROVISIONING TYPE 001b of VPD 0x82.

    The device server shall able to all LBAs reported in the RETURNED LOGICAL BLOCK ADDRESS field of the READ CAPACITY (10).

    This is often used by SSD where SSD firmware need to know which block/sector is not used.

    But why SSD firmware need to know unused block/sector?

    In short, SSD firmware don't have to read original data on overwrite action from group page if all blocks in that page is marked as unused.

    Detail from Wikipedia:

  • Thin provisioned: PROVISIONING TYPE 010b of VPD 0x82.

    The device server can indicate a larger capacity in the RETURNED LOGICAL BLOCK ADDRESS field of the READ CAPACITY (10) then amiable LBAs.

    Often used in SAN for saving unused capacity -- over booking but not used.

The Provisioning type could be checked via command:

$ sudo sg_vpd --page=0xb2 /dev/sda
Logical block provisioning VPD page (SBC):
  Unmap command supported (LBPU): 0
  Write same (16) with unmap bit supported (LBWS): 1
  Write same (10) with unmap bit supported (LBWS10): 0
  Logical block provisioning read zeros (LBPRZ): 0
  Anchored LBAs supported (ANC_SUP): 0
  Threshold exponent: 0
  Descriptor present (DP): 0
  Minimum percentage: 0
  Provisioning type: 0
  Threshold percentage: 0

To do unmap operation, device server shall support at least one of the following unmap mechanisms:

  • The UNMAP 0x42 command.

  • The UNMAP bit in the WRITE SAME (10) 0x41 command or WRITE SAME (16) 0x93 command or WRITE SAME (32) 0x7f command.

Linux kernel implementation

The kernel read the Logical block provisioning(LBP) VPD 0xb2 page and Block limits(BL) VPD 0xb0 page to find out which unmap mechanism should be used.

  • If LBP VPD is not supported:

    • Use UNMAP command if BL VPD says MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT bigger than 1.
    • Use Write same 16 command otherwise.
  • If LBP VPD is supported:

    • Use UNMAP 0x42 command if LBP VPD says LBUP is 1.
    • Use WRITE SAME (16) 0x93 command if LBP VPD says LBPWS is 1.
    • Use WRITE SAME (10) 0x41 command if LBP VPD says LBPWS10 is 1.
    • Disable unmap support otherwise.

Linux kernel related codes:

The function sd_read_block_limits() in driver/scsi/sd.c is called every time a new scsi disk found: (linux kernel code version: v4.14.13)

		if (!sdkp->lbpvpd) { /* LBP VPD page not provided */

			if (sdkp->max_unmap_blocks)
				sd_config_discard(sdkp, SD_LBP_UNMAP);
			else
				sd_config_discard(sdkp, SD_LBP_WS16);

		} else {	/* LBP VPD page tells us what to use */
			if (sdkp->lbpu && sdkp->max_unmap_blocks)
				sd_config_discard(sdkp, SD_LBP_UNMAP);
			else if (sdkp->lbpws)
				sd_config_discard(sdkp, SD_LBP_WS16);
			else if (sdkp->lbpws10)
				sd_config_discard(sdkp, SD_LBP_WS10);
			else
				sd_config_discard(sdkp, SD_LBP_DISABLE);
		}

The write same 32 is not supported by linux by v4.14.13 yet.

From userspace, you may check the provisioning mode via command:

$ for x in /sys/class/scsi_disk/* ; do  echo $x; cat $x/provisioning_mode; done
/sys/class/scsi_disk/0:0:0:0
writesame_16
/sys/class/scsi_disk/4:0:0:0
full

To query LBP VPD page:

$ sudo sg_vpd --page=lbpv /dev/sda
Logical block provisioning VPD page (SBC):
  Unmap command supported (LBPU): 0
  Write same (16) with unmap bit supported (LBWS): 1
  Write same (10) with unmap bit supported (LBWS10): 0
  Logical block provisioning read zeros (LBPRZ): 0
  Anchored LBAs supported (ANC_SUP): 0
  Threshold exponent: 0
  Descriptor present (DP): 0
  Minimum percentage: 0
  Provisioning type: 0
  Threshold percentage: 0

To query BL VPD page:

$ sudo sg_vpd --page=bl /dev/sda
Block limits VPD page (SBC):
  Write same non-zero (WSNZ): 0
  Maximum compare and write length: 0 blocks
  Optimal transfer length granularity: 1 blocks
  Maximum transfer length: 0 blocks
  Optimal transfer length: 0 blocks
  Maximum prefetch length: 0 blocks
  Maximum unmap LBA count: 0
  Maximum unmap block descriptor count: 0
  Optimal unmap granularity: 1
  Unmap granularity alignment valid: 0
  Unmap granularity alignment: 0
  Maximum write same length: 0x3fffc0 blocks
  Maximum atomic transfer length: 0
  Atomic alignment: 0
  Atomic transfer length granularity: 0
  Maximum atomic transfer length with atomic boundary: 0
  Maximum atomic boundary size: 0

To test UNMAP command, try sg_umap. To test WRITE SAME 10 or 16 or 32, try sg_write_same.

@tmm1
Copy link

tmm1 commented Jan 8, 2022

Thanks for documenting this!

Note that the linux scsi maintainer is working on improving the logic used to set provisioning_mode in the kernel here: https://git.kernel.org/pub/scm/linux/kernel/git/mkp/linux.git/log/?h=5.18/discovery

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment