From patchwork Mon Jun 6 17:58:10 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shaun Tancheff X-Patchwork-Id: 631073 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3rNj9j5LDzz9t41 for ; Tue, 7 Jun 2016 03:58:33 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751969AbcFFR6c (ORCPT ); Mon, 6 Jun 2016 13:58:32 -0400 Received: from smtp81.mediacombb.net ([68.66.77.81]:42126 "EHLO dsmdc-mail-smtp.mcomdc.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751951AbcFFR6b (ORCPT ); Mon, 6 Jun 2016 13:58:31 -0400 Received: from helios ([173.23.250.243]) by njtocomv02.mcomdc.com with bizsmtp id 3VyU1t00N5FqEsV01VyUdw; Mon, 06 Jun 2016 13:58:29 -0400 X-Outbound-Route: TO X-Authenticated-Sender: shaun@helios.aeonazure.com X-Authority-Analysis: v=2.1 cv=LMPoQfm9 c=1 sm=1 tr=0 a=OCiMecrhrNRzvyrd/uXHhg==:117 a=OCiMecrhrNRzvyrd/uXHhg==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=pD_ry4oyNxEA:10 a=3go8odswAAAA:8 a=2ebQZRPgDGNMPkmoTo8A:9 a=WCphLhRDQySbTNkkd-8K:22 X-Authenticated-Sender: shaun@helios.aeonazure.com Received: from shaun by helios with local (Exim 4.87) (envelope-from ) id 1b9ynE-0006OF-6O; Mon, 06 Jun 2016 12:58:28 -0500 From: Shaun Tancheff To: linux-ide@vger.kernel.org, linux-scsi@vger.kernel.org Cc: Shaun Tancheff , Shaun Tancheff Subject: [PATCH] Add support for SCT Write Same Date: Mon, 6 Jun 2016 12:58:10 -0500 Message-Id: <1465235890-15703-2-git-send-email-shaun@tancheff.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1465235890-15703-1-git-send-email-shaun@tancheff.com> References: <1465235890-15703-1-git-send-email-shaun@tancheff.com> Sender: linux-ide-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ide@vger.kernel.org SATA drives may support write same via SCT. This is useful for setting the drive contents to a specific pattern (0's). Signed-off-by: Shaun Tancheff --- drivers/ata/libata-scsi.c | 31 +++++++++++++++++++++++++ drivers/scsi/sd.c | 25 +++++++++++--------- include/linux/ata.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++ include/scsi/scsi_device.h | 1 + 4 files changed, 104 insertions(+), 11 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index bfec66f..4f1a97b 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3305,6 +3305,37 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) goto invalid_param_len; buf = page_address(sg_page(scsi_sglist(scmd))); + + if (ata_id_sct_write_same(dev->id)) { + u16 *sctpg = buf; + + put_unaligned_le16(0x0002, &sctpg[0]); /* SCT_ACT_WRITE_SAME */ + put_unaligned_le16(0x0101, &sctpg[1]); /* WRITE PTRN FG */ + put_unaligned_le64(block, &sctpg[2]); + put_unaligned_le64(n_block, &sctpg[6]); + put_unaligned_le32(0u, &sctpg[10]); + + tf->hob_feature = 0; + tf->feature = 0; + tf->hob_nsect = 0; + tf->nsect = 1; + tf->lbah = 0; + tf->lbam = 0; + tf->lbal = ATA_CMD_STANDBYNOW1; + tf->hob_lbah = 0; + tf->hob_lbam = 0; + tf->hob_lbal = 0; + tf->device = ATA_CMD_STANDBYNOW1; + tf->protocol = ATA_PROT_DMA; + tf->command = ATA_CMD_WRITE_LOG_DMA_EXT; + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | + ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE; + + ata_qc_set_pc_nbytes(qc); + + return 0; + } + size = ata_set_lba_range_entries(buf, 512, block, n_block); if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) { diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 428c03e..c5c8424 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -794,7 +795,7 @@ static void sd_config_write_same(struct scsi_disk *sdkp) struct request_queue *q = sdkp->disk->queue; unsigned int logical_block_size = sdkp->device->sector_size; - if (sdkp->device->no_write_same) { + if (sdkp->device->no_write_same && !sdkp->device->sct_write_same) { sdkp->max_ws_blocks = 0; goto out; } @@ -2761,24 +2762,26 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) { struct scsi_device *sdev = sdkp->device; - if (sdev->host->no_write_same) { - sdev->no_write_same = 1; - - return; - } - if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) { - /* too large values might cause issues with arcmsr */ - int vpd_buf_len = 64; - sdev->no_report_opcodes = 1; /* Disable WRITE SAME if REPORT SUPPORTED OPERATION * CODES is unsupported and the device has an ATA * Information VPD page (SAT). */ - if (!scsi_get_vpd_page(sdev, 0x89, buffer, vpd_buf_len)) + if (!scsi_get_vpd_page(sdev, 0x89, buffer, SD_BUF_SIZE)) { sdev->no_write_same = 1; + if (ata_id_sct_write_same((u16 *)&buffer[60])) { + sdev->sct_write_same = 1; + sdkp->max_ws_blocks = SD_MAX_WS16_BLOCKS; + } + } + } + + if (sdev->host->no_write_same) { + sdev->no_write_same = 1; + + return; } if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16) == 1) diff --git a/include/linux/ata.h b/include/linux/ata.h index 99346be..cdffe1f 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -104,6 +104,7 @@ enum { ATA_ID_CFA_KEY_MGMT = 162, ATA_ID_CFA_MODES = 163, ATA_ID_DATA_SET_MGMT = 169, + ATA_ID_SCT_CMD_XPORT = 206, ATA_ID_ROT_SPEED = 217, ATA_ID_PIO4 = (1 << 1), @@ -778,6 +779,48 @@ static inline bool ata_id_sense_reporting_enabled(const u16 *id) } /** + * + * Word: 206 - SCT Command Transport + * 15:12 - Vendor Specific + * 11:6 - Reserved + * 5 - SCT Command Transport Data Tables supported + * 4 - SCT Command Transport Features Control supported + * 3 - SCT Command Transport Error Recovery Control supported + * 2 - SCT Command Transport Write Same supported + * 1 - SCT Command Transport Long Sector Access supported + * 0 - SCT Command Transport supported + */ +static inline bool ata_id_sct_data_tables(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 5) ? true : false; +} + +static inline bool ata_id_sct_features_ctrl(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 4) ? true : false; +} + +static inline bool ata_id_sct_error_recovery_ctrl(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 3) ? true : false; +} + +static inline bool ata_id_sct_write_same(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 2) ? true : false; +} + +static inline bool ata_id_sct_long_sector_access(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 1) ? true : false; +} + +static inline bool ata_id_sct_supported(const u16 *id) +{ + return id[ATA_ID_SCT_CMD_XPORT] & (1 << 0) ? true : false; +} + +/** * ata_id_major_version - get ATA level of drive * @id: Identify data * @@ -1060,6 +1103,21 @@ static inline void ata_id_to_hd_driveid(u16 *id) #endif } +/** + * _lba_to_cmd_ata() - Copy lba48 to ATA command + * @cmd: ATA command as an array of bytes + * @_lba: lba48 in the low 48 bits + */ +static inline void _lba_to_cmd_ata(u8 *cmd, u64 _lba) +{ + cmd[1] = _lba & 0xff; + cmd[3] = (_lba >> 8) & 0xff; + cmd[5] = (_lba >> 16) & 0xff; + cmd[0] = (_lba >> 24) & 0xff; + cmd[2] = (_lba >> 32) & 0xff; + cmd[4] = (_lba >> 40) & 0xff; +} + /* * Write LBA Range Entries to the buffer that will cover the extent from * sector to sector + count. This is used for TRIM and for ADD LBA(S) diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index a6c346d..66f5af7 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -157,6 +157,7 @@ struct scsi_device { unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */ unsigned no_write_same:1; /* no WRITE SAME command */ + unsigned sct_write_same:1; /* Has WRITE SAME via SCT Command */ unsigned use_16_for_rw:1; /* Use read/write(16) over read/write(10) */ unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */