Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libata: SCT Write Same / DSM Trim

Correct handling of devices with sector_size other that 512 bytes.

In the case of a 4Kn device sector_size it is possible to describe a much
larger DSM Trim than the current fixed default of 512 bytes.

This patch assumes the minimum descriptor is sector_size and fills out
the descriptor accordingly.

The ACS-2 specification is quite clear that the DSM command payload is
sized as number of 512 byte transfers so a 4Kn device will operate
correctly without this patch.

Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
Acked-by: Tejun Heo <tj@kernel.org>

authored by

Shaun Tancheff and committed by
Tejun Heo
ef2d7392 7b203094

+57 -28
+57 -28
drivers/ata/libata-scsi.c
··· 3283 3283 /** 3284 3284 * ata_format_dsm_trim_descr() - SATL Write Same to DSM Trim 3285 3285 * @cmd: SCSI command being translated 3286 - * @num: Maximum number of entries (nominally 64). 3286 + * @trmax: Maximum number of entries that will fit in sector_size bytes. 3287 3287 * @sector: Starting sector 3288 3288 * @count: Total Range of request in logical sectors 3289 3289 * ··· 3298 3298 * LBA's should be sorted order and not overlap. 3299 3299 * 3300 3300 * NOTE: this is the same format as ADD LBA(S) TO NV CACHE PINNED SET 3301 + * 3302 + * Return: Number of bytes copied into sglist. 3301 3303 */ 3302 - static unsigned int ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 num, 3303 - u64 sector, u32 count) 3304 + static size_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax, 3305 + u64 sector, u32 count) 3304 3306 { 3305 - __le64 *buffer; 3306 - u32 i = 0, used_bytes; 3307 + struct scsi_device *sdp = cmd->device; 3308 + size_t len = sdp->sector_size; 3309 + size_t r; 3310 + __le64 *buf; 3311 + u32 i = 0; 3307 3312 unsigned long flags; 3308 3313 3309 - BUILD_BUG_ON(512 > ATA_SCSI_RBUF_SIZE); 3314 + WARN_ON(len > ATA_SCSI_RBUF_SIZE); 3315 + 3316 + if (len > ATA_SCSI_RBUF_SIZE) 3317 + len = ATA_SCSI_RBUF_SIZE; 3310 3318 3311 3319 spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); 3312 - buffer = ((void *)ata_scsi_rbuf); 3313 - while (i < num) { 3320 + buf = ((void *)ata_scsi_rbuf); 3321 + memset(buf, 0, len); 3322 + while (i < trmax) { 3314 3323 u64 entry = sector | 3315 3324 ((u64)(count > 0xffff ? 0xffff : count) << 48); 3316 - buffer[i++] = __cpu_to_le64(entry); 3325 + buf[i++] = __cpu_to_le64(entry); 3317 3326 if (count <= 0xffff) 3318 3327 break; 3319 3328 count -= 0xffff; 3320 3329 sector += 0xffff; 3321 3330 } 3322 - 3323 - used_bytes = ALIGN(i * 8, 512); 3324 - memset(buffer + i, 0, used_bytes - i * 8); 3325 - sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buffer, 512); 3331 + r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, len); 3326 3332 spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); 3327 3333 3328 - return used_bytes; 3334 + return r; 3329 3335 } 3330 3336 3331 3337 /** 3332 3338 * ata_format_dsm_trim_descr() - SATL Write Same to ATA SCT Write Same 3333 3339 * @cmd: SCSI command being translated 3334 3340 * @lba: Starting sector 3335 - * @num: Number of logical sectors to be zero'd. 3341 + * @num: Number of sectors to be zero'd. 3336 3342 * 3337 - * Rewrite the WRITE SAME descriptor to be an SCT Write Same formatted 3343 + * Rewrite the WRITE SAME payload to be an SCT Write Same formatted 3338 3344 * descriptor. 3339 3345 * NOTE: Writes a pattern (0's) in the foreground. 3340 - * Large write-same requents can timeout. 3346 + * 3347 + * Return: Number of bytes copied into sglist. 3341 3348 */ 3342 - static void ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, u64 num) 3349 + static size_t ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, u64 num) 3343 3350 { 3344 - u16 *sctpg; 3351 + struct scsi_device *sdp = cmd->device; 3352 + size_t len = sdp->sector_size; 3353 + size_t r; 3354 + u16 *buf; 3345 3355 unsigned long flags; 3346 3356 3347 3357 spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); 3348 - sctpg = ((void *)ata_scsi_rbuf); 3358 + buf = ((void *)ata_scsi_rbuf); 3349 3359 3350 - put_unaligned_le16(0x0002, &sctpg[0]); /* SCT_ACT_WRITE_SAME */ 3351 - put_unaligned_le16(0x0101, &sctpg[1]); /* WRITE PTRN FG */ 3352 - put_unaligned_le64(lba, &sctpg[2]); 3353 - put_unaligned_le64(num, &sctpg[6]); 3354 - put_unaligned_le32(0u, &sctpg[10]); 3360 + put_unaligned_le16(0x0002, &buf[0]); /* SCT_ACT_WRITE_SAME */ 3361 + put_unaligned_le16(0x0101, &buf[1]); /* WRITE PTRN FG */ 3362 + put_unaligned_le64(lba, &buf[2]); 3363 + put_unaligned_le64(num, &buf[6]); 3364 + put_unaligned_le32(0u, &buf[10]); /* pattern */ 3355 3365 3356 - sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), sctpg, 512); 3366 + WARN_ON(len > ATA_SCSI_RBUF_SIZE); 3367 + 3368 + if (len > ATA_SCSI_RBUF_SIZE) 3369 + len = ATA_SCSI_RBUF_SIZE; 3370 + 3371 + r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, len); 3357 3372 spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); 3373 + 3374 + return r; 3358 3375 } 3359 3376 3360 3377 /** ··· 3388 3371 { 3389 3372 struct ata_taskfile *tf = &qc->tf; 3390 3373 struct scsi_cmnd *scmd = qc->scsicmd; 3374 + struct scsi_device *sdp = scmd->device; 3375 + size_t len = sdp->sector_size; 3391 3376 struct ata_device *dev = qc->dev; 3392 3377 const u8 *cdb = scmd->cmnd; 3393 3378 u64 block; 3394 3379 u32 n_block; 3395 - const u32 trmax = ATA_MAX_TRIM_RNUM; 3380 + const u32 trmax = len >> 3; 3396 3381 u32 size; 3397 3382 u16 fp; 3398 3383 u8 bp = 0xff; ··· 3439 3420 if (!scsi_sg_count(scmd)) 3440 3421 goto invalid_param_len; 3441 3422 3423 + /* 3424 + * size must match sector size in bytes 3425 + * For DATA SET MANAGEMENT TRIM in ACS-2 nsect (aka count) 3426 + * is defined as number of 512 byte blocks to be transferred. 3427 + */ 3442 3428 if (unmap) { 3443 3429 size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block); 3430 + if (size != len) 3431 + goto invalid_param_len; 3432 + 3444 3433 if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) { 3445 3434 /* Newer devices support queued TRIM commands */ 3446 3435 tf->protocol = ATA_PROT_NCQ; ··· 3468 3441 tf->command = ATA_CMD_DSM; 3469 3442 } 3470 3443 } else { 3471 - ata_format_sct_write_same(scmd, block, n_block); 3444 + size = ata_format_sct_write_same(scmd, block, n_block); 3445 + if (size != len) 3446 + goto invalid_param_len; 3472 3447 3473 3448 tf->hob_feature = 0; 3474 3449 tf->feature = 0;