Commit 045d3fe7 authored by Martin K. Petersen's avatar Martin K. Petersen Committed by James Bottomley

[SCSI] sd: Update thin provisioning support

Add support for the Thin Provisioning VPD page and use the TPU and TPWS
bits to switch between UNMAP and WRITE SAME(16) for discards.  If no TP
VPD page is present we fall back to old scheme where the max descriptor
count combined with the max lba count are used trigger UNMAP.
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent a36c61f9
...@@ -2039,14 +2039,24 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) ...@@ -2039,14 +2039,24 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
lba_count = get_unaligned_be32(&buffer[20]); lba_count = get_unaligned_be32(&buffer[20]);
desc_count = get_unaligned_be32(&buffer[24]); desc_count = get_unaligned_be32(&buffer[24]);
if (lba_count) { if (lba_count && desc_count) {
q->limits.max_discard_sectors = if (sdkp->tpvpd && !sdkp->tpu)
lba_count * sector_sz >> 9; sdkp->unmap = 0;
else
if (desc_count)
sdkp->unmap = 1; sdkp->unmap = 1;
} }
if (sdkp->tpvpd && !sdkp->tpu && !sdkp->tpws) {
sd_printk(KERN_ERR, sdkp, "Thin provisioning is " \
"enabled but neither TPU, nor TPWS are " \
"set. Disabling discard!\n");
goto out;
}
if (lba_count)
q->limits.max_discard_sectors =
lba_count * sector_sz >> 9;
granularity = get_unaligned_be32(&buffer[28]); granularity = get_unaligned_be32(&buffer[28]);
if (granularity) if (granularity)
...@@ -2087,6 +2097,31 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) ...@@ -2087,6 +2097,31 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
kfree(buffer); kfree(buffer);
} }
/**
* sd_read_thin_provisioning - Query thin provisioning VPD page
* @disk: disk to query
*/
static void sd_read_thin_provisioning(struct scsi_disk *sdkp)
{
unsigned char *buffer;
const int vpd_len = 8;
if (sdkp->thin_provisioning == 0)
return;
buffer = kmalloc(vpd_len, GFP_KERNEL);
if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb2, buffer, vpd_len))
goto out;
sdkp->tpvpd = 1;
sdkp->tpu = (buffer[5] >> 7) & 1; /* UNMAP */
sdkp->tpws = (buffer[5] >> 6) & 1; /* WRITE SAME(16) with UNMAP */
out:
kfree(buffer);
}
static int sd_try_extended_inquiry(struct scsi_device *sdp) static int sd_try_extended_inquiry(struct scsi_device *sdp)
{ {
/* /*
...@@ -2138,6 +2173,7 @@ static int sd_revalidate_disk(struct gendisk *disk) ...@@ -2138,6 +2173,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
sd_read_capacity(sdkp, buffer); sd_read_capacity(sdkp, buffer);
if (sd_try_extended_inquiry(sdp)) { if (sd_try_extended_inquiry(sdp)) {
sd_read_thin_provisioning(sdkp);
sd_read_block_limits(sdkp); sd_read_block_limits(sdkp);
sd_read_block_characteristics(sdkp); sd_read_block_characteristics(sdkp);
} }
......
...@@ -63,6 +63,9 @@ struct scsi_disk { ...@@ -63,6 +63,9 @@ struct scsi_disk {
unsigned first_scan : 1; unsigned first_scan : 1;
unsigned thin_provisioning : 1; unsigned thin_provisioning : 1;
unsigned unmap : 1; unsigned unmap : 1;
unsigned tpws : 1;
unsigned tpu : 1;
unsigned tpvpd : 1;
}; };
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment