diff options
author | Shaun Tancheff <shaun@tancheff.com> | 2016-08-22 00:23:18 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2016-08-25 11:26:48 -0400 |
commit | 9379e6b8e0f995365dc6158a1463c8dab4f2c8da (patch) | |
tree | 22d3a77eaa583229d0f7cfba7d9dec04aa64839c /drivers/ata | |
parent | cd27396e6103a43c3df76f70db1feafa16206471 (diff) |
libata: Safely overwrite attached page in WRITE SAME xlat
Safely overwriting the attached page to ATA format from the SCSI formatted
variant.
Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-scsi.c | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index be9c76c938b2..84e7f48ca83e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -3282,6 +3282,54 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) | |||
3282 | return 1; | 3282 | return 1; |
3283 | } | 3283 | } |
3284 | 3284 | ||
3285 | /** | ||
3286 | * ata_format_dsm_trim_descr() - SATL Write Same to DSM Trim | ||
3287 | * @cmd: SCSI command being translated | ||
3288 | * @num: Maximum number of entries (nominally 64). | ||
3289 | * @sector: Starting sector | ||
3290 | * @count: Total Range of request | ||
3291 | * | ||
3292 | * Rewrite the WRITE SAME descriptor to be a DSM TRIM little-endian formatted | ||
3293 | * descriptor. | ||
3294 | * | ||
3295 | * Upto 64 entries of the format: | ||
3296 | * 63:48 Range Length | ||
3297 | * 47:0 LBA | ||
3298 | * | ||
3299 | * Range Length of 0 is ignored. | ||
3300 | * LBA's should be sorted order and not overlap. | ||
3301 | * | ||
3302 | * NOTE: this is the same format as ADD LBA(S) TO NV CACHE PINNED SET | ||
3303 | */ | ||
3304 | static unsigned int ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 num, | ||
3305 | u64 sector, u32 count) | ||
3306 | { | ||
3307 | __le64 *buffer; | ||
3308 | u32 i = 0, used_bytes; | ||
3309 | unsigned long flags; | ||
3310 | |||
3311 | BUILD_BUG_ON(512 > ATA_SCSI_RBUF_SIZE); | ||
3312 | |||
3313 | spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); | ||
3314 | buffer = ((void *)ata_scsi_rbuf); | ||
3315 | while (i < num) { | ||
3316 | u64 entry = sector | | ||
3317 | ((u64)(count > 0xffff ? 0xffff : count) << 48); | ||
3318 | buffer[i++] = __cpu_to_le64(entry); | ||
3319 | if (count <= 0xffff) | ||
3320 | break; | ||
3321 | count -= 0xffff; | ||
3322 | sector += 0xffff; | ||
3323 | } | ||
3324 | |||
3325 | used_bytes = ALIGN(i * 8, 512); | ||
3326 | memset(buffer + i, 0, used_bytes - i * 8); | ||
3327 | sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buffer, 512); | ||
3328 | spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); | ||
3329 | |||
3330 | return used_bytes; | ||
3331 | } | ||
3332 | |||
3285 | static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) | 3333 | static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) |
3286 | { | 3334 | { |
3287 | struct ata_taskfile *tf = &qc->tf; | 3335 | struct ata_taskfile *tf = &qc->tf; |
@@ -3290,8 +3338,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) | |||
3290 | const u8 *cdb = scmd->cmnd; | 3338 | const u8 *cdb = scmd->cmnd; |
3291 | u64 block; | 3339 | u64 block; |
3292 | u32 n_block; | 3340 | u32 n_block; |
3341 | const u32 trmax = ATA_MAX_TRIM_RNUM; | ||
3293 | u32 size; | 3342 | u32 size; |
3294 | void *buf; | ||
3295 | u16 fp; | 3343 | u16 fp; |
3296 | u8 bp = 0xff; | 3344 | u8 bp = 0xff; |
3297 | 3345 | ||
@@ -3319,10 +3367,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) | |||
3319 | if (!scsi_sg_count(scmd)) | 3367 | if (!scsi_sg_count(scmd)) |
3320 | goto invalid_param_len; | 3368 | goto invalid_param_len; |
3321 | 3369 | ||
3322 | buf = page_address(sg_page(scsi_sglist(scmd))); | 3370 | if (n_block <= 0xffff * trmax) { |
3323 | 3371 | size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block); | |
3324 | if (n_block <= 65535 * ATA_MAX_TRIM_RNUM) { | ||
3325 | size = ata_set_lba_range_entries(buf, ATA_MAX_TRIM_RNUM, block, n_block); | ||
3326 | } else { | 3372 | } else { |
3327 | fp = 2; | 3373 | fp = 2; |
3328 | goto invalid_fld; | 3374 | goto invalid_fld; |