diff options
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 98 |
1 files changed, 69 insertions, 29 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ff4c9a3aa5b2..57d1e3e1bd44 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -477,7 +477,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) { - rq->timeout = SD_TIMEOUT; + rq->timeout = SD_FLUSH_TIMEOUT; rq->retries = SD_MAX_RETRIES; rq->cmd[0] = SYNCHRONIZE_CACHE; rq->cmd_len = 10; @@ -1072,7 +1072,7 @@ static int sd_sync_cache(struct scsi_disk *sdkp) * flush everything. */ res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, - SD_TIMEOUT, SD_MAX_RETRIES, NULL); + SD_FLUSH_TIMEOUT, SD_MAX_RETRIES, NULL); if (res == 0) break; } @@ -1557,7 +1557,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, } /* Logical blocks per physical block exponent */ - sdkp->hw_sector_size = (1 << (buffer[13] & 0xf)) * sector_size; + sdkp->physical_block_size = (1 << (buffer[13] & 0xf)) * sector_size; /* Lowest aligned logical block */ alignment = ((buffer[14] & 0x3f) << 8 | buffer[15]) * sector_size; @@ -1570,7 +1570,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, struct request_queue *q = sdp->request_queue; sdkp->thin_provisioning = 1; - q->limits.discard_granularity = sdkp->hw_sector_size; + q->limits.discard_granularity = sdkp->physical_block_size; q->limits.max_discard_sectors = 0xffffffff; if (buffer[14] & 0x40) /* TPRZ */ @@ -1634,7 +1634,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp, 0xffffffff when the want to report a size of 0 (with which they really mean no media is present) */ sdkp->capacity = 0; - sdkp->hw_sector_size = sector_size; + sdkp->physical_block_size = sector_size; return sector_size; } @@ -1647,7 +1647,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp, } sdkp->capacity = lba + 1; - sdkp->hw_sector_size = sector_size; + sdkp->physical_block_size = sector_size; return sector_size; } @@ -1768,10 +1768,10 @@ got_data: (unsigned long long)sdkp->capacity, sector_size, cap_str_10, cap_str_2); - if (sdkp->hw_sector_size != sector_size) + if (sdkp->physical_block_size != sector_size) sd_printk(KERN_NOTICE, sdkp, "%u-byte physical blocks\n", - sdkp->hw_sector_size); + sdkp->physical_block_size); } } @@ -1785,7 +1785,8 @@ got_data: else if (sector_size == 256) sdkp->capacity >>= 1; - blk_queue_physical_block_size(sdp->request_queue, sdkp->hw_sector_size); + blk_queue_physical_block_size(sdp->request_queue, + sdkp->physical_block_size); sdkp->device->sector_size = sector_size; } @@ -2051,14 +2052,24 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) lba_count = get_unaligned_be32(&buffer[20]); desc_count = get_unaligned_be32(&buffer[24]); - if (lba_count) { - q->limits.max_discard_sectors = - lba_count * sector_sz >> 9; - - if (desc_count) + if (lba_count && desc_count) { + if (sdkp->tpvpd && !sdkp->tpu) + sdkp->unmap = 0; + else 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]); if (granularity) @@ -2099,6 +2110,31 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) 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) { /* @@ -2121,7 +2157,7 @@ static int sd_revalidate_disk(struct gendisk *disk) struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; unsigned char *buffer; - unsigned ordered; + unsigned flush = 0; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_revalidate_disk\n")); @@ -2150,6 +2186,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_capacity(sdkp, buffer); if (sd_try_extended_inquiry(sdp)) { + sd_read_thin_provisioning(sdkp); sd_read_block_limits(sdkp); sd_read_block_characteristics(sdkp); } @@ -2163,17 +2200,15 @@ static int sd_revalidate_disk(struct gendisk *disk) /* * We now have all cache related info, determine how we deal - * with ordered requests. Note that as the current SCSI - * dispatch function can alter request order, we cannot use - * QUEUE_ORDERED_TAG_* even when ordered tag is supported. + * with flush requests. */ - if (sdkp->WCE) - ordered = sdkp->DPOFUA - ? QUEUE_ORDERED_DRAIN_FUA : QUEUE_ORDERED_DRAIN_FLUSH; - else - ordered = QUEUE_ORDERED_DRAIN; + if (sdkp->WCE) { + flush |= REQ_FLUSH; + if (sdkp->DPOFUA) + flush |= REQ_FUA; + } - blk_queue_ordered(sdkp->disk->queue, ordered); + blk_queue_flush(sdkp->disk->queue, flush); set_capacity(disk, sdkp->capacity); kfree(buffer); @@ -2264,11 +2299,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie) index = sdkp->index; dev = &sdp->sdev_gendev; - if (index < SD_MAX_DISKS) { - gd->major = sd_major((index & 0xf0) >> 4); - gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); - gd->minors = SD_MINORS; - } + gd->major = sd_major((index & 0xf0) >> 4); + gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); + gd->minors = SD_MINORS; + gd->fops = &sd_fops; gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; @@ -2358,6 +2392,12 @@ static int sd_probe(struct device *dev) if (error) goto out_put; + if (index >= SD_MAX_DISKS) { + error = -ENODEV; + sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name space exhausted.\n"); + goto out_free_index; + } + error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN); if (error) goto out_free_index; |