sd: Export preferred I/O sizes Make storage devices that support the Block Limits VPD export the optimal transfer length granularity and the optimal transfer length to the block layer. Signed-off-by: Martin K. Petersen --- diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1341,6 +1341,10 @@ got_data: hard_sector, (unsigned long long)mb); } + disk_topology_set(sdkp->disk, 0, IOT_REGION_START, 0); + disk_topology_set(sdkp->disk, 0, IOT_REGION_LENGTH, + sdkp->capacity * sector_size); + /* Rescale capacity to 512-byte units */ if (sector_size == 4096) sdkp->capacity <<= 3; @@ -1535,6 +1539,50 @@ defaults: } /** + * sd_block_limits - Query disk device for preferred I/O sizes. + * @disk: disk to query + * @buffer: temporary buffer to store inquiry response in + */ +static void sd_block_limits(struct scsi_disk *sdkp, unsigned char *buffer) +{ + /* Block Limits VPD */ + if (scsi_get_vpd_page(sdkp->device, buffer, 0xb0, 16) < 0) + return; + + disk_topology_set(sdkp->disk, 0, IOT_PHYS_OFF, 0); + disk_topology_set(sdkp->disk, 0, IOT_OPT_BLOCK_SIZE, + be16_to_cpup((__be16 *)&buffer[6]) + * sdkp->device->sector_size); + disk_topology_set(sdkp->disk, 0, IOT_MAX_IO_LENGTH, + be32_to_cpup((__be32 *)&buffer[8]) + * sdkp->device->sector_size); + disk_topology_set(sdkp->disk, 0, IOT_OPT_IO_LENTGH, + be32_to_cpup((__be32 *)&buffer[12]) + * sdkp->device->sector_size); +} + +/** + * sd_block_characteristics - Query block dev. characteristics + * @disk: disk to query + * @buffer: temporary buffer to store inquiry response in + */ +static void sd_block_characteristics(struct scsi_disk *sdkp, unsigned char *buffer) +{ + unsigned int rotation; + + /* Block Device Characteristics VPD */ + if (scsi_get_vpd_page(sdkp->device, buffer, 0xb1, 64) < 0) + return; + + rotation = be16_to_cpup((__be16 *)&buffer[4]); + + if (rotation == 1) + disk_topology_set(sdkp->disk, 0, IOT_DEV_TYPE, IOT_TYPE_SSD); + else if (rotation > 0x400) + disk_topology_set(sdkp->disk, 0, IOT_DEV_TYPE, IOT_TYPE_DISK); +} + +/** * sd_revalidate_disk - called the first time a new disk is seen, * performs disk spin up, read_capacity, etc. * @disk: struct gendisk we care about @@ -1579,6 +1627,8 @@ static int sd_revalidate_disk(struct gen */ if (sdkp->media_present) { sd_read_capacity(sdkp, buffer); + sd_block_limits(sdkp, buffer); + sd_block_characteristics(sdkp, buffer); sd_read_write_protect_flag(sdkp, buffer); sd_read_cache_type(sdkp, buffer); } @@ -1703,8 +1753,6 @@ static int sd_probe(struct device *dev) gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; - sd_revalidate_disk(gd); - blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); gd->driverfs_dev = &sdp->sdev_gendev; @@ -1714,6 +1762,12 @@ static int sd_probe(struct device *dev) dev_set_drvdata(dev, sdkp); add_disk(gd); + + disk_topology_register(gd); + disk_topology_add_region(gd, 0, 0); + disk_topology_add_region(gd, 10, 20); + + sd_revalidate_disk(gd); sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sdp->removable ? "removable " : ""); @@ -1744,6 +1798,7 @@ static int sd_remove(struct device *dev) struct scsi_disk *sdkp = dev_get_drvdata(dev); device_del(&sdkp->dev); + disk_topology_unregister(sdkp->disk); del_gendisk(sdkp->disk); sd_shutdown(dev);