diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/scsi/sd.c | 107 | ||||
| -rw-r--r-- | drivers/scsi/sd.h | 2 |
2 files changed, 109 insertions, 0 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9093c7261f33..255da53e5a01 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
| @@ -264,6 +264,15 @@ sd_show_app_tag_own(struct device *dev, struct device_attribute *attr, | |||
| 264 | return snprintf(buf, 20, "%u\n", sdkp->ATO); | 264 | return snprintf(buf, 20, "%u\n", sdkp->ATO); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | static ssize_t | ||
| 268 | sd_show_thin_provisioning(struct device *dev, struct device_attribute *attr, | ||
| 269 | char *buf) | ||
| 270 | { | ||
| 271 | struct scsi_disk *sdkp = to_scsi_disk(dev); | ||
| 272 | |||
| 273 | return snprintf(buf, 20, "%u\n", sdkp->thin_provisioning); | ||
| 274 | } | ||
| 275 | |||
| 267 | static struct device_attribute sd_disk_attrs[] = { | 276 | static struct device_attribute sd_disk_attrs[] = { |
| 268 | __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, | 277 | __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, |
| 269 | sd_store_cache_type), | 278 | sd_store_cache_type), |
| @@ -274,6 +283,7 @@ static struct device_attribute sd_disk_attrs[] = { | |||
| 274 | sd_store_manage_start_stop), | 283 | sd_store_manage_start_stop), |
| 275 | __ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL), | 284 | __ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL), |
| 276 | __ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL), | 285 | __ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL), |
| 286 | __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL), | ||
| 277 | __ATTR_NULL, | 287 | __ATTR_NULL, |
| 278 | }; | 288 | }; |
| 279 | 289 | ||
| @@ -399,6 +409,57 @@ static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif) | |||
| 399 | } | 409 | } |
| 400 | 410 | ||
| 401 | /** | 411 | /** |
| 412 | * sd_prepare_discard - unmap blocks on thinly provisioned device | ||
| 413 | * @rq: Request to prepare | ||
| 414 | * | ||
| 415 | * Will issue either UNMAP or WRITE SAME(16) depending on preference | ||
| 416 | * indicated by target device. | ||
| 417 | **/ | ||
| 418 | static int sd_prepare_discard(struct request *rq) | ||
| 419 | { | ||
| 420 | struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); | ||
| 421 | struct bio *bio = rq->bio; | ||
| 422 | sector_t sector = bio->bi_sector; | ||
| 423 | unsigned int num = bio_sectors(bio); | ||
| 424 | |||
| 425 | if (sdkp->device->sector_size == 4096) { | ||
| 426 | sector >>= 3; | ||
| 427 | num >>= 3; | ||
| 428 | } | ||
| 429 | |||
| 430 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | ||
| 431 | rq->timeout = SD_TIMEOUT; | ||
| 432 | |||
| 433 | memset(rq->cmd, 0, rq->cmd_len); | ||
| 434 | |||
| 435 | if (sdkp->unmap) { | ||
| 436 | char *buf = kmap_atomic(bio_page(bio), KM_USER0); | ||
| 437 | |||
| 438 | rq->cmd[0] = UNMAP; | ||
| 439 | rq->cmd[8] = 24; | ||
| 440 | rq->cmd_len = 10; | ||
| 441 | |||
| 442 | /* Ensure that data length matches payload */ | ||
| 443 | rq->__data_len = bio->bi_size = bio->bi_io_vec->bv_len = 24; | ||
| 444 | |||
| 445 | put_unaligned_be16(6 + 16, &buf[0]); | ||
| 446 | put_unaligned_be16(16, &buf[2]); | ||
| 447 | put_unaligned_be64(sector, &buf[8]); | ||
| 448 | put_unaligned_be32(num, &buf[16]); | ||
| 449 | |||
| 450 | kunmap_atomic(buf, KM_USER0); | ||
| 451 | } else { | ||
| 452 | rq->cmd[0] = WRITE_SAME_16; | ||
| 453 | rq->cmd[1] = 0x8; /* UNMAP */ | ||
| 454 | put_unaligned_be64(sector, &rq->cmd[2]); | ||
| 455 | put_unaligned_be32(num, &rq->cmd[10]); | ||
| 456 | rq->cmd_len = 16; | ||
| 457 | } | ||
| 458 | |||
| 459 | return BLKPREP_OK; | ||
| 460 | } | ||
| 461 | |||
| 462 | /** | ||
| 402 | * sd_init_command - build a scsi (read or write) command from | 463 | * sd_init_command - build a scsi (read or write) command from |
| 403 | * information in the request structure. | 464 | * information in the request structure. |
| 404 | * @SCpnt: pointer to mid-level's per scsi command structure that | 465 | * @SCpnt: pointer to mid-level's per scsi command structure that |
| @@ -418,6 +479,13 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 418 | int ret, host_dif; | 479 | int ret, host_dif; |
| 419 | unsigned char protect; | 480 | unsigned char protect; |
| 420 | 481 | ||
| 482 | /* | ||
| 483 | * Discard request come in as REQ_TYPE_FS but we turn them into | ||
| 484 | * block PC requests to make life easier. | ||
| 485 | */ | ||
| 486 | if (blk_discard_rq(rq)) | ||
| 487 | ret = sd_prepare_discard(rq); | ||
| 488 | |||
| 421 | if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { | 489 | if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { |
| 422 | ret = scsi_setup_blk_pc_cmnd(sdp, rq); | 490 | ret = scsi_setup_blk_pc_cmnd(sdp, rq); |
| 423 | goto out; | 491 | goto out; |
| @@ -1432,6 +1500,19 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, | |||
| 1432 | sd_printk(KERN_NOTICE, sdkp, | 1500 | sd_printk(KERN_NOTICE, sdkp, |
| 1433 | "physical block alignment offset: %u\n", alignment); | 1501 | "physical block alignment offset: %u\n", alignment); |
| 1434 | 1502 | ||
| 1503 | if (buffer[14] & 0x80) { /* TPE */ | ||
| 1504 | struct request_queue *q = sdp->request_queue; | ||
| 1505 | |||
| 1506 | sdkp->thin_provisioning = 1; | ||
| 1507 | q->limits.discard_granularity = sdkp->hw_sector_size; | ||
| 1508 | q->limits.max_discard_sectors = 0xffffffff; | ||
| 1509 | |||
| 1510 | if (buffer[14] & 0x40) /* TPRZ */ | ||
| 1511 | q->limits.discard_zeroes_data = 1; | ||
| 1512 | |||
| 1513 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); | ||
| 1514 | } | ||
| 1515 | |||
| 1435 | sdkp->capacity = lba + 1; | 1516 | sdkp->capacity = lba + 1; |
| 1436 | return sector_size; | 1517 | return sector_size; |
| 1437 | } | 1518 | } |
| @@ -1863,6 +1944,7 @@ void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) | |||
| 1863 | */ | 1944 | */ |
| 1864 | static void sd_read_block_limits(struct scsi_disk *sdkp) | 1945 | static void sd_read_block_limits(struct scsi_disk *sdkp) |
| 1865 | { | 1946 | { |
| 1947 | struct request_queue *q = sdkp->disk->queue; | ||
| 1866 | unsigned int sector_sz = sdkp->device->sector_size; | 1948 | unsigned int sector_sz = sdkp->device->sector_size; |
| 1867 | char *buffer; | 1949 | char *buffer; |
| 1868 | 1950 | ||
| @@ -1877,6 +1959,31 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) | |||
| 1877 | blk_queue_io_opt(sdkp->disk->queue, | 1959 | blk_queue_io_opt(sdkp->disk->queue, |
| 1878 | get_unaligned_be32(&buffer[12]) * sector_sz); | 1960 | get_unaligned_be32(&buffer[12]) * sector_sz); |
| 1879 | 1961 | ||
| 1962 | /* Thin provisioning enabled and page length indicates TP support */ | ||
| 1963 | if (sdkp->thin_provisioning && buffer[3] == 0x3c) { | ||
| 1964 | unsigned int lba_count, desc_count, granularity; | ||
| 1965 | |||
| 1966 | lba_count = get_unaligned_be32(&buffer[20]); | ||
| 1967 | desc_count = get_unaligned_be32(&buffer[24]); | ||
| 1968 | |||
| 1969 | if (lba_count) { | ||
| 1970 | q->limits.max_discard_sectors = | ||
| 1971 | lba_count * sector_sz >> 9; | ||
| 1972 | |||
| 1973 | if (desc_count) | ||
| 1974 | sdkp->unmap = 1; | ||
| 1975 | } | ||
| 1976 | |||
| 1977 | granularity = get_unaligned_be32(&buffer[28]); | ||
| 1978 | |||
| 1979 | if (granularity) | ||
| 1980 | q->limits.discard_granularity = granularity * sector_sz; | ||
| 1981 | |||
| 1982 | if (buffer[32] & 0x80) | ||
| 1983 | q->limits.discard_alignment = | ||
| 1984 | get_unaligned_be32(&buffer[32]) & ~(1 << 31); | ||
| 1985 | } | ||
| 1986 | |||
| 1880 | kfree(buffer); | 1987 | kfree(buffer); |
| 1881 | } | 1988 | } |
| 1882 | 1989 | ||
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index e374804d26fb..43d3caf268ef 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
| @@ -60,6 +60,8 @@ struct scsi_disk { | |||
| 60 | unsigned RCD : 1; /* state of disk RCD bit, unused */ | 60 | unsigned RCD : 1; /* state of disk RCD bit, unused */ |
| 61 | unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ | 61 | unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ |
| 62 | unsigned first_scan : 1; | 62 | unsigned first_scan : 1; |
| 63 | unsigned thin_provisioning : 1; | ||
| 64 | unsigned unmap : 1; | ||
| 63 | }; | 65 | }; |
| 64 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) | 66 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) |
| 65 | 67 | ||
