diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/sd.c | 46 | ||||
-rw-r--r-- | drivers/scsi/sd.h | 3 |
2 files changed, 44 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 | */ | ||
2104 | static 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 | |||
2090 | static int sd_try_extended_inquiry(struct scsi_device *sdp) | 2125 | static 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 | } |
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 315ce9d96b1f..a40730ee465c 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
@@ -63,6 +63,9 @@ struct scsi_disk { | |||
63 | unsigned first_scan : 1; | 63 | unsigned first_scan : 1; |
64 | unsigned thin_provisioning : 1; | 64 | unsigned thin_provisioning : 1; |
65 | unsigned unmap : 1; | 65 | unsigned unmap : 1; |
66 | unsigned tpws : 1; | ||
67 | unsigned tpu : 1; | ||
68 | unsigned tpvpd : 1; | ||
66 | }; | 69 | }; |
67 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) | 70 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) |
68 | 71 | ||