aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sd.c
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2010-09-10 01:22:07 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-09-17 13:07:55 -0400
commit045d3fe766b01921e24e2d4178e011b3b09ad4d6 (patch)
treeae0d69a0181def3bea7e7387d79e61ee943cc940 /drivers/scsi/sd.c
parenta36c61f9025b8924f99f54d518763bee7aa84085 (diff)
[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: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r--drivers/scsi/sd.c46
1 files changed, 41 insertions, 5 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 8c9b275f71a7..0c4f89cfb7dc 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2039,14 +2039,24 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
2039 lba_count = get_unaligned_be32(&buffer[20]); 2039 lba_count = get_unaligned_be32(&buffer[20]);
2040 desc_count = get_unaligned_be32(&buffer[24]); 2040 desc_count = get_unaligned_be32(&buffer[24]);
2041 2041
2042 if (lba_count) { 2042 if (lba_count && desc_count) {
2043 q->limits.max_discard_sectors = 2043 if (sdkp->tpvpd && !sdkp->tpu)
2044 lba_count * sector_sz >> 9; 2044 sdkp->unmap = 0;
2045 2045 else
2046 if (desc_count)
2047 sdkp->unmap = 1; 2046 sdkp->unmap = 1;
2048 } 2047 }
2049 2048
2049 if (sdkp->tpvpd && !sdkp->tpu && !sdkp->tpws) {
2050 sd_printk(KERN_ERR, sdkp, "Thin provisioning is " \
2051 "enabled but neither TPU, nor TPWS are " \
2052 "set. Disabling discard!\n");
2053 goto out;
2054 }
2055
2056 if (lba_count)
2057 q->limits.max_discard_sectors =
2058 lba_count * sector_sz >> 9;
2059
2050 granularity = get_unaligned_be32(&buffer[28]); 2060 granularity = get_unaligned_be32(&buffer[28]);
2051 2061
2052 if (granularity) 2062 if (granularity)
@@ -2087,6 +2097,31 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
2087 kfree(buffer); 2097 kfree(buffer);
2088} 2098}
2089 2099
2100/**
2101 * sd_read_thin_provisioning - Query thin provisioning VPD page
2102 * @disk: disk to query
2103 */
2104static void sd_read_thin_provisioning(struct scsi_disk *sdkp)
2105{
2106 unsigned char *buffer;
2107 const int vpd_len = 8;
2108
2109 if (sdkp->thin_provisioning == 0)
2110 return;
2111
2112 buffer = kmalloc(vpd_len, GFP_KERNEL);
2113
2114 if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb2, buffer, vpd_len))
2115 goto out;
2116
2117 sdkp->tpvpd = 1;
2118 sdkp->tpu = (buffer[5] >> 7) & 1; /* UNMAP */
2119 sdkp->tpws = (buffer[5] >> 6) & 1; /* WRITE SAME(16) with UNMAP */
2120
2121 out:
2122 kfree(buffer);
2123}
2124
2090static int sd_try_extended_inquiry(struct scsi_device *sdp) 2125static int sd_try_extended_inquiry(struct scsi_device *sdp)
2091{ 2126{
2092 /* 2127 /*
@@ -2138,6 +2173,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
2138 sd_read_capacity(sdkp, buffer); 2173 sd_read_capacity(sdkp, buffer);
2139 2174
2140 if (sd_try_extended_inquiry(sdp)) { 2175 if (sd_try_extended_inquiry(sdp)) {
2176 sd_read_thin_provisioning(sdkp);
2141 sd_read_block_limits(sdkp); 2177 sd_read_block_limits(sdkp);
2142 sd_read_block_characteristics(sdkp); 2178 sd_read_block_characteristics(sdkp);
2143 } 2179 }