On Mon, 2014-06-02 at 15:11 -0400, Martin K. Petersen wrote:
> Until now the per-command transfer length has exclusively been gated by
> the max_sectors parameter in the scsi_host template. Given that the size
> of this parameter has been bumped to an unsigned int we have to be
> careful not to exceed the target device's capabilities.
> 
> If the if the device specifies a Maximum Transfer Length in the Block
> Limits VPD we'll use that value. Otherwise we'll use 0xffffffff for
> devices that have use_16_for_rw set and 0xffff for the rest. We then
> combine the chosen disk limit with max_sectors in the host template. The
> smaller of the two will be used to set the max_hw_sectors queue limit.
> 
> Signed-off-by: Martin K. Petersen <[email protected]>
> 
> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
> index 321faf603035..56018f37518d 100644
> --- a/drivers/scsi/sd.c
> +++ b/drivers/scsi/sd.c
> @@ -2228,7 +2228,11 @@ got_data:
>               }
>       }
>  
> -     sdp->use_16_for_rw = (sdkp->capacity > 0xffffffff);
> +     if (sdkp->capacity > 0xffffffff) {
> +             sdp->use_16_for_rw = 1;
> +             sdkp->max_xfer_blocks = SD_MAX_XFER_BLOCKS;
> +     } else
> +             sdkp->max_xfer_blocks = SD_DEF_XFER_BLOCKS;
>  
>       /* Rescale capacity to 512-byte units */
>       if (sector_size == 4096)
> @@ -2540,6 +2544,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
>  {
>       unsigned int sector_sz = sdkp->device->sector_size;
>       const int vpd_len = 64;
> +     u32 max_xfer_length;
>       unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
>  
>       if (!buffer ||
> @@ -2547,6 +2552,10 @@ static void sd_read_block_limits(struct scsi_disk 
> *sdkp)
>           scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len))
>               goto out;
>  
> +     max_xfer_length = get_unaligned_be32(&buffer[8]);
> +     if (max_xfer_length)
> +             sdkp->max_xfer_blocks = max_xfer_length;
> +
>       blk_queue_io_min(sdkp->disk->queue,
>                        get_unaligned_be16(&buffer[6]) * sector_sz);
>       blk_queue_io_opt(sdkp->disk->queue,
> @@ -2702,6 +2711,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
>       struct scsi_device *sdp = sdkp->device;
>       unsigned char *buffer;
>       unsigned flush = 0;
> +     unsigned int max_xfer;
>  
>       SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp,
>                                     "sd_revalidate_disk\n"));
> @@ -2755,6 +2765,10 @@ static int sd_revalidate_disk(struct gendisk *disk)
>  
>       blk_queue_flush(sdkp->disk->queue, flush);
>  
> +     max_xfer = min_not_zero((unsigned int)sdp->host->max_sectors,
> +                             (unsigned int)sdkp->max_xfer_blocks);
> +     max_xfer <<= ilog2(sdp->sector_size) - 9;
> +     blk_queue_max_hw_sectors(sdkp->disk->queue, max_xfer);
>       set_capacity(disk, sdkp->capacity);
>       sd_config_write_same(sdkp);
>       kfree(buffer);
> diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
> index 620871efbf0a..4c3ab8377fd3 100644
> --- a/drivers/scsi/sd.h
> +++ b/drivers/scsi/sd.h
> @@ -44,6 +44,8 @@ enum {
>  };
>  
>  enum {
> +     SD_DEF_XFER_BLOCKS = 0xffff,
> +     SD_MAX_XFER_BLOCKS = 0xffffffff,
>       SD_MAX_WS10_BLOCKS = 0xffff,
>       SD_MAX_WS16_BLOCKS = 0x7fffff,
>  };
> @@ -64,6 +66,7 @@ struct scsi_disk {
>       struct gendisk  *disk;
>       atomic_t        openers;
>       sector_t        capacity;       /* size in 512-byte sectors */
> +     u32             max_xfer_blocks;
>       u32             max_ws_blocks;
>       u32             max_unmap_blocks;
>       u32             unmap_granularity;
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to [email protected]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Looks good.

Reviewed-by: Ewan D. Milne <[email protected]>


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to