diff options
author | Shaun Tancheff <shaun@tancheff.com> | 2016-08-22 00:23:19 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2016-08-25 11:26:48 -0400 |
commit | 7b20309428598df00ffeb0b01f5948dea6aaf1f7 (patch) | |
tree | 101fa3f176dc5f3829e000852913a514a7fa068c | |
parent | 9379e6b8e0f995365dc6158a1463c8dab4f2c8da (diff) |
libata: Add support for SCT Write Same
SATA drives may support write same via SCT. This is useful
for setting the drive contents to a specific pattern (0's).
Translate a SCSI WRITE SAME 16 command to be either a DSM TRIM
command or an SCT Write Same command.
Based on the UNMAP flag:
- When set translate to DSM TRIM
- When not set translate to SCT Write Same
Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
-rw-r--r-- | drivers/ata/libata-scsi.c | 199 | ||||
-rw-r--r-- | include/linux/ata.h | 43 |
2 files changed, 213 insertions, 29 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 84e7f48ca83e..08d9c8e731b3 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -1159,8 +1159,6 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) | |||
1159 | { | 1159 | { |
1160 | sdev->use_10_for_rw = 1; | 1160 | sdev->use_10_for_rw = 1; |
1161 | sdev->use_10_for_ms = 1; | 1161 | sdev->use_10_for_ms = 1; |
1162 | sdev->no_report_opcodes = 1; | ||
1163 | sdev->no_write_same = 1; | ||
1164 | 1162 | ||
1165 | /* Schedule policy is determined by ->qc_defer() callback and | 1163 | /* Schedule policy is determined by ->qc_defer() callback and |
1166 | * it needs to see every deferred qc. Set dev_blocked to 1 to | 1164 | * it needs to see every deferred qc. Set dev_blocked to 1 to |
@@ -3287,7 +3285,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) | |||
3287 | * @cmd: SCSI command being translated | 3285 | * @cmd: SCSI command being translated |
3288 | * @num: Maximum number of entries (nominally 64). | 3286 | * @num: Maximum number of entries (nominally 64). |
3289 | * @sector: Starting sector | 3287 | * @sector: Starting sector |
3290 | * @count: Total Range of request | 3288 | * @count: Total Range of request in logical sectors |
3291 | * | 3289 | * |
3292 | * Rewrite the WRITE SAME descriptor to be a DSM TRIM little-endian formatted | 3290 | * Rewrite the WRITE SAME descriptor to be a DSM TRIM little-endian formatted |
3293 | * descriptor. | 3291 | * descriptor. |
@@ -3330,6 +3328,45 @@ static unsigned int ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 num, | |||
3330 | return used_bytes; | 3328 | return used_bytes; |
3331 | } | 3329 | } |
3332 | 3330 | ||
3331 | /** | ||
3332 | * ata_format_dsm_trim_descr() - SATL Write Same to ATA SCT Write Same | ||
3333 | * @cmd: SCSI command being translated | ||
3334 | * @lba: Starting sector | ||
3335 | * @num: Number of logical sectors to be zero'd. | ||
3336 | * | ||
3337 | * Rewrite the WRITE SAME descriptor to be an SCT Write Same formatted | ||
3338 | * descriptor. | ||
3339 | * NOTE: Writes a pattern (0's) in the foreground. | ||
3340 | * Large write-same requents can timeout. | ||
3341 | */ | ||
3342 | static void ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, u64 num) | ||
3343 | { | ||
3344 | u16 *sctpg; | ||
3345 | unsigned long flags; | ||
3346 | |||
3347 | spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); | ||
3348 | sctpg = ((void *)ata_scsi_rbuf); | ||
3349 | |||
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]); | ||
3355 | |||
3356 | sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), sctpg, 512); | ||
3357 | spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); | ||
3358 | } | ||
3359 | |||
3360 | /** | ||
3361 | * ata_scsi_write_same_xlat() - SATL Write Same to ATA SCT Write Same | ||
3362 | * @qc: Command to be translated | ||
3363 | * | ||
3364 | * Translate a SCSI WRITE SAME command to be either a DSM TRIM command or | ||
3365 | * an SCT Write Same command. | ||
3366 | * Based on WRITE SAME has the UNMAP flag | ||
3367 | * When set translate to DSM TRIM | ||
3368 | * When clear translate to SCT Write Same | ||
3369 | */ | ||
3333 | static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) | 3370 | static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) |
3334 | { | 3371 | { |
3335 | struct ata_taskfile *tf = &qc->tf; | 3372 | struct ata_taskfile *tf = &qc->tf; |
@@ -3342,6 +3379,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) | |||
3342 | u32 size; | 3379 | u32 size; |
3343 | u16 fp; | 3380 | u16 fp; |
3344 | u8 bp = 0xff; | 3381 | u8 bp = 0xff; |
3382 | u8 unmap = cdb[1] & 0x8; | ||
3345 | 3383 | ||
3346 | /* we may not issue DMA commands if no DMA mode is set */ | 3384 | /* we may not issue DMA commands if no DMA mode is set */ |
3347 | if (unlikely(!dev->dma_mode)) | 3385 | if (unlikely(!dev->dma_mode)) |
@@ -3353,11 +3391,26 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) | |||
3353 | } | 3391 | } |
3354 | scsi_16_lba_len(cdb, &block, &n_block); | 3392 | scsi_16_lba_len(cdb, &block, &n_block); |
3355 | 3393 | ||
3356 | /* for now we only support WRITE SAME with the unmap bit set */ | 3394 | if (unmap) { |
3357 | if (unlikely(!(cdb[1] & 0x8))) { | 3395 | /* If trim is not enabled the cmd is invalid. */ |
3358 | fp = 1; | 3396 | if ((dev->horkage & ATA_HORKAGE_NOTRIM) || |
3359 | bp = 3; | 3397 | !ata_id_has_trim(dev->id)) { |
3360 | goto invalid_fld; | 3398 | fp = 1; |
3399 | bp = 3; | ||
3400 | goto invalid_fld; | ||
3401 | } | ||
3402 | /* If the request is too large the cmd is invalid */ | ||
3403 | if (n_block > 0xffff * trmax) { | ||
3404 | fp = 2; | ||
3405 | goto invalid_fld; | ||
3406 | } | ||
3407 | } else { | ||
3408 | /* If write same is not available the cmd is invalid */ | ||
3409 | if (!ata_id_sct_write_same(dev->id)) { | ||
3410 | fp = 1; | ||
3411 | bp = 3; | ||
3412 | goto invalid_fld; | ||
3413 | } | ||
3361 | } | 3414 | } |
3362 | 3415 | ||
3363 | /* | 3416 | /* |
@@ -3367,30 +3420,42 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) | |||
3367 | if (!scsi_sg_count(scmd)) | 3420 | if (!scsi_sg_count(scmd)) |
3368 | goto invalid_param_len; | 3421 | goto invalid_param_len; |
3369 | 3422 | ||
3370 | if (n_block <= 0xffff * trmax) { | 3423 | if (unmap) { |
3371 | size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block); | 3424 | size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block); |
3425 | if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) { | ||
3426 | /* Newer devices support queued TRIM commands */ | ||
3427 | tf->protocol = ATA_PROT_NCQ; | ||
3428 | tf->command = ATA_CMD_FPDMA_SEND; | ||
3429 | tf->hob_nsect = ATA_SUBCMD_FPDMA_SEND_DSM & 0x1f; | ||
3430 | tf->nsect = qc->tag << 3; | ||
3431 | tf->hob_feature = (size / 512) >> 8; | ||
3432 | tf->feature = size / 512; | ||
3433 | |||
3434 | tf->auxiliary = 1; | ||
3435 | } else { | ||
3436 | tf->protocol = ATA_PROT_DMA; | ||
3437 | tf->hob_feature = 0; | ||
3438 | tf->feature = ATA_DSM_TRIM; | ||
3439 | tf->hob_nsect = (size / 512) >> 8; | ||
3440 | tf->nsect = size / 512; | ||
3441 | tf->command = ATA_CMD_DSM; | ||
3442 | } | ||
3372 | } else { | 3443 | } else { |
3373 | fp = 2; | 3444 | ata_format_sct_write_same(scmd, block, n_block); |
3374 | goto invalid_fld; | ||
3375 | } | ||
3376 | |||
3377 | if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) { | ||
3378 | /* Newer devices support queued TRIM commands */ | ||
3379 | tf->protocol = ATA_PROT_NCQ; | ||
3380 | tf->command = ATA_CMD_FPDMA_SEND; | ||
3381 | tf->hob_nsect = ATA_SUBCMD_FPDMA_SEND_DSM & 0x1f; | ||
3382 | tf->nsect = qc->tag << 3; | ||
3383 | tf->hob_feature = (size / 512) >> 8; | ||
3384 | tf->feature = size / 512; | ||
3385 | 3445 | ||
3386 | tf->auxiliary = 1; | ||
3387 | } else { | ||
3388 | tf->protocol = ATA_PROT_DMA; | ||
3389 | tf->hob_feature = 0; | 3446 | tf->hob_feature = 0; |
3390 | tf->feature = ATA_DSM_TRIM; | 3447 | tf->feature = 0; |
3391 | tf->hob_nsect = (size / 512) >> 8; | 3448 | tf->hob_nsect = 0; |
3392 | tf->nsect = size / 512; | 3449 | tf->nsect = 1; |
3393 | tf->command = ATA_CMD_DSM; | 3450 | tf->lbah = 0; |
3451 | tf->lbam = 0; | ||
3452 | tf->lbal = ATA_CMD_STANDBYNOW1; | ||
3453 | tf->hob_lbah = 0; | ||
3454 | tf->hob_lbam = 0; | ||
3455 | tf->hob_lbal = 0; | ||
3456 | tf->device = ATA_CMD_STANDBYNOW1; | ||
3457 | tf->protocol = ATA_PROT_DMA; | ||
3458 | tf->command = ATA_CMD_WRITE_LOG_DMA_EXT; | ||
3394 | } | 3459 | } |
3395 | 3460 | ||
3396 | tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | | 3461 | tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | |
@@ -3414,6 +3479,76 @@ invalid_opcode: | |||
3414 | } | 3479 | } |
3415 | 3480 | ||
3416 | /** | 3481 | /** |
3482 | * ata_scsiop_maint_in - Simulate a subset of MAINTENANCE_IN | ||
3483 | * @args: device MAINTENANCE_IN data / SCSI command of interest. | ||
3484 | * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. | ||
3485 | * | ||
3486 | * Yields a subset to satisfy scsi_report_opcode() | ||
3487 | * | ||
3488 | * LOCKING: | ||
3489 | * spin_lock_irqsave(host lock) | ||
3490 | */ | ||
3491 | static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) | ||
3492 | { | ||
3493 | struct ata_device *dev = args->dev; | ||
3494 | u8 *cdb = args->cmd->cmnd; | ||
3495 | u8 supported = 0; | ||
3496 | unsigned int err = 0; | ||
3497 | |||
3498 | if (cdb[2] != 1) { | ||
3499 | ata_dev_warn(dev, "invalid command format %d\n", cdb[2]); | ||
3500 | err = 2; | ||
3501 | goto out; | ||
3502 | } | ||
3503 | switch (cdb[3]) { | ||
3504 | case INQUIRY: | ||
3505 | case MODE_SENSE: | ||
3506 | case MODE_SENSE_10: | ||
3507 | case READ_CAPACITY: | ||
3508 | case SERVICE_ACTION_IN_16: | ||
3509 | case REPORT_LUNS: | ||
3510 | case REQUEST_SENSE: | ||
3511 | case SYNCHRONIZE_CACHE: | ||
3512 | case REZERO_UNIT: | ||
3513 | case SEEK_6: | ||
3514 | case SEEK_10: | ||
3515 | case TEST_UNIT_READY: | ||
3516 | case SEND_DIAGNOSTIC: | ||
3517 | case MAINTENANCE_IN: | ||
3518 | case READ_6: | ||
3519 | case READ_10: | ||
3520 | case READ_16: | ||
3521 | case WRITE_6: | ||
3522 | case WRITE_10: | ||
3523 | case WRITE_16: | ||
3524 | case ATA_12: | ||
3525 | case ATA_16: | ||
3526 | case VERIFY: | ||
3527 | case VERIFY_16: | ||
3528 | case MODE_SELECT: | ||
3529 | case MODE_SELECT_10: | ||
3530 | case START_STOP: | ||
3531 | supported = 3; | ||
3532 | break; | ||
3533 | case WRITE_SAME_16: | ||
3534 | if (ata_id_sct_write_same(dev->id)) | ||
3535 | supported = 3; | ||
3536 | break; | ||
3537 | case ZBC_IN: | ||
3538 | case ZBC_OUT: | ||
3539 | if (ata_id_zoned_cap(dev->id) || | ||
3540 | dev->class == ATA_DEV_ZAC) | ||
3541 | supported = 3; | ||
3542 | break; | ||
3543 | default: | ||
3544 | break; | ||
3545 | } | ||
3546 | out: | ||
3547 | rbuf[1] = supported; /* supported */ | ||
3548 | return err; | ||
3549 | } | ||
3550 | |||
3551 | /** | ||
3417 | * ata_scsi_report_zones_complete - convert ATA output | 3552 | * ata_scsi_report_zones_complete - convert ATA output |
3418 | * @qc: command structure returning the data | 3553 | * @qc: command structure returning the data |
3419 | * | 3554 | * |
@@ -4193,6 +4328,13 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) | |||
4193 | ata_scsi_invalid_field(dev, cmd, 1); | 4328 | ata_scsi_invalid_field(dev, cmd, 1); |
4194 | break; | 4329 | break; |
4195 | 4330 | ||
4331 | case MAINTENANCE_IN: | ||
4332 | if (scsicmd[1] == MI_REPORT_SUPPORTED_OPERATION_CODES) | ||
4333 | ata_scsi_rbuf_fill(&args, ata_scsiop_maint_in); | ||
4334 | else | ||
4335 | ata_scsi_invalid_field(dev, cmd, 1); | ||
4336 | break; | ||
4337 | |||
4196 | /* all other commands */ | 4338 | /* all other commands */ |
4197 | default: | 4339 | default: |
4198 | ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0); | 4340 | ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0); |
@@ -4225,7 +4367,6 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) | |||
4225 | shost->max_lun = 1; | 4367 | shost->max_lun = 1; |
4226 | shost->max_channel = 1; | 4368 | shost->max_channel = 1; |
4227 | shost->max_cmd_len = 16; | 4369 | shost->max_cmd_len = 16; |
4228 | shost->no_write_same = 1; | ||
4229 | 4370 | ||
4230 | /* Schedule policy is determined by ->qc_defer() | 4371 | /* Schedule policy is determined by ->qc_defer() |
4231 | * callback and it needs to see every deferred qc. | 4372 | * callback and it needs to see every deferred qc. |
diff --git a/include/linux/ata.h b/include/linux/ata.h index 45a1d71c55f1..fdb180367ba1 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h | |||
@@ -105,6 +105,7 @@ enum { | |||
105 | ATA_ID_CFA_KEY_MGMT = 162, | 105 | ATA_ID_CFA_KEY_MGMT = 162, |
106 | ATA_ID_CFA_MODES = 163, | 106 | ATA_ID_CFA_MODES = 163, |
107 | ATA_ID_DATA_SET_MGMT = 169, | 107 | ATA_ID_DATA_SET_MGMT = 169, |
108 | ATA_ID_SCT_CMD_XPORT = 206, | ||
108 | ATA_ID_ROT_SPEED = 217, | 109 | ATA_ID_ROT_SPEED = 217, |
109 | ATA_ID_PIO4 = (1 << 1), | 110 | ATA_ID_PIO4 = (1 << 1), |
110 | 111 | ||
@@ -789,6 +790,48 @@ static inline bool ata_id_sense_reporting_enabled(const u16 *id) | |||
789 | } | 790 | } |
790 | 791 | ||
791 | /** | 792 | /** |
793 | * | ||
794 | * Word: 206 - SCT Command Transport | ||
795 | * 15:12 - Vendor Specific | ||
796 | * 11:6 - Reserved | ||
797 | * 5 - SCT Command Transport Data Tables supported | ||
798 | * 4 - SCT Command Transport Features Control supported | ||
799 | * 3 - SCT Command Transport Error Recovery Control supported | ||
800 | * 2 - SCT Command Transport Write Same supported | ||
801 | * 1 - SCT Command Transport Long Sector Access supported | ||
802 | * 0 - SCT Command Transport supported | ||
803 | */ | ||
804 | static inline bool ata_id_sct_data_tables(const u16 *id) | ||
805 | { | ||
806 | return id[ATA_ID_SCT_CMD_XPORT] & (1 << 5) ? true : false; | ||
807 | } | ||
808 | |||
809 | static inline bool ata_id_sct_features_ctrl(const u16 *id) | ||
810 | { | ||
811 | return id[ATA_ID_SCT_CMD_XPORT] & (1 << 4) ? true : false; | ||
812 | } | ||
813 | |||
814 | static inline bool ata_id_sct_error_recovery_ctrl(const u16 *id) | ||
815 | { | ||
816 | return id[ATA_ID_SCT_CMD_XPORT] & (1 << 3) ? true : false; | ||
817 | } | ||
818 | |||
819 | static inline bool ata_id_sct_write_same(const u16 *id) | ||
820 | { | ||
821 | return id[ATA_ID_SCT_CMD_XPORT] & (1 << 2) ? true : false; | ||
822 | } | ||
823 | |||
824 | static inline bool ata_id_sct_long_sector_access(const u16 *id) | ||
825 | { | ||
826 | return id[ATA_ID_SCT_CMD_XPORT] & (1 << 1) ? true : false; | ||
827 | } | ||
828 | |||
829 | static inline bool ata_id_sct_supported(const u16 *id) | ||
830 | { | ||
831 | return id[ATA_ID_SCT_CMD_XPORT] & (1 << 0) ? true : false; | ||
832 | } | ||
833 | |||
834 | /** | ||
792 | * ata_id_major_version - get ATA level of drive | 835 | * ata_id_major_version - get ATA level of drive |
793 | * @id: Identify data | 836 | * @id: Identify data |
794 | * | 837 | * |