From patchwork Mon Jun 20 15:03:48 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shaun Tancheff X-Patchwork-Id: 9187737 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 6CA2F6075E for ; Mon, 20 Jun 2016 15:05:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5ABBE26861 for ; Mon, 20 Jun 2016 15:05:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4F9352766D; Mon, 20 Jun 2016 15:05:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6E85E26861 for ; Mon, 20 Jun 2016 15:05:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753334AbcFTPFs (ORCPT ); Mon, 20 Jun 2016 11:05:48 -0400 Received: from smtp78.mediacombb.net ([68.66.77.78]:54483 "EHLO dsmdc-mail-smtp.mcomdc.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1755467AbcFTPFB (ORCPT ); Mon, 20 Jun 2016 11:05:01 -0400 Received: from helios ([173.23.250.243]) by njtocomv03.mcomdc.com with bizsmtp id 934D1t00P5FqEsV0134Etn; Mon, 20 Jun 2016 11:04:15 -0400 X-Outbound-Route: TO X-Authenticated-Sender: shaun@helios.aeonazure.com X-Authority-Analysis: v=2.1 cv=J7wk7WXS 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=xJLe47kqochyD5wTQhwA:9 a=VrxFbCK3jA5WF0yv:21 a=ZAFG5vVmZrnbueDv:21 a=WCphLhRDQySbTNkkd-8K:22 X-Authenticated-Sender: shaun@helios.aeonazure.com Received: from shaun by helios with local (Exim 4.87) (envelope-from ) id 1bF0kH-0003ck-JN; Mon, 20 Jun 2016 10:04:13 -0500 From: Shaun Tancheff To: linux-ide@vger.kernel.org, linux-scsi@vger.kernel.org Cc: Shaun Tancheff , "James E . J . Bottomley" , "Martin K . Petersen" , Tejun Heo , Christoph Hellwig , Shaun Tancheff Subject: [PATCH v3] Add support for SCT Write Same Date: Mon, 20 Jun 2016 10:03:48 -0500 Message-Id: <1466435028-13886-2-git-send-email-shaun@tancheff.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1466435028-13886-1-git-send-email-shaun@tancheff.com> References: <1466435028-13886-1-git-send-email-shaun@tancheff.com> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP SATA drives may support write same via SCT. This is useful for setting the drive contents to a specific pattern (0's). If UNMAP is not set or TRIM is not available then fall back to SCT WRITE SAME, if it is available. In this way it would be possible to mimic lbprz for devices that support TRIM but fail to zero blocks reliably. For example a file-system or DM target could issue a write same w/o unmap followed by an trim. Signed-off-by: Shaun Tancheff --- v3: - Demux UNMAP/TRIM from WRITE SAME v2: - Remove fugly ata hacking from sd.c --- drivers/ata/libata-scsi.c | 80 +++++++++++++++++++++++++++++++++++----------- drivers/scsi/sd.c | 2 +- include/linux/ata.h | 43 +++++++++++++++++++++++++ include/scsi/scsi_device.h | 1 + 4 files changed, 106 insertions(+), 20 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index bfec66f..3dcc29e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1204,6 +1204,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, if (!ata_id_has_unload(dev->id)) dev->flags |= ATA_DFLAG_NO_UNLOAD; + if (ata_id_sct_write_same(dev->id)) + sdev->sct_write_same = 1; + /* configure max sectors */ blk_queue_max_hw_sectors(q, dev->max_sectors); @@ -3272,6 +3275,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) struct ata_taskfile *tf = &qc->tf; struct scsi_cmnd *scmd = qc->scsicmd; struct ata_device *dev = qc->dev; + struct scatterlist *sg; const u8 *cdb = scmd->cmnd; u64 block; u32 n_block; @@ -3279,6 +3283,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) void *buf; u16 fp; u8 bp = 0xff; + u8 unmap = cdb[1] & 0x8; + bool use_sct = (unmap && ata_id_has_trim(dev->id)) ? false : true; /* we may not issue DMA commands if no DMA mode is set */ if (unlikely(!dev->dma_mode)) @@ -3290,8 +3296,14 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) } scsi_16_lba_len(cdb, &block, &n_block); - /* for now we only support WRITE SAME with the unmap bit set */ - if (unlikely(!(cdb[1] & 0x8))) { + /* effectivly ignore had_trim if NOTRIM horkage is flagged */ + if (dev->horkage & ATA_HORKAGE_NOTRIM) + use_sct = true; + + /* + * If use_sct and SCT write same is not available then fail. + */ + if (use_sct && !ata_id_sct_write_same(dev->id)) { fp = 1; bp = 3; goto invalid_fld; @@ -3304,26 +3316,56 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) if (!scsi_sg_count(scmd)) goto invalid_param_len; - buf = page_address(sg_page(scsi_sglist(scmd))); - size = ata_set_lba_range_entries(buf, 512, block, n_block); + sg = scsi_sglist(scmd); + buf = page_address(sg_page(sg)) + sg->offset; - if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) { - /* Newer devices support queued TRIM commands */ - tf->protocol = ATA_PROT_NCQ; - tf->command = ATA_CMD_FPDMA_SEND; - tf->hob_nsect = ATA_SUBCMD_FPDMA_SEND_DSM & 0x1f; - tf->nsect = qc->tag << 3; - tf->hob_feature = (size / 512) >> 8; - tf->feature = size / 512; + /* + * if we only have SCT then ignore the state of unmap request + * a zero the blocks. + */ + if (use_sct) { + 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->auxiliary = 1; - } else { - tf->protocol = ATA_PROT_DMA; tf->hob_feature = 0; - tf->feature = ATA_DSM_TRIM; - tf->hob_nsect = (size / 512) >> 8; - tf->nsect = size / 512; - tf->command = ATA_CMD_DSM; + 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; + } else { + size = ata_set_lba_range_entries(buf, 512, block, n_block); + + if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) { + /* Newer devices support queued TRIM commands */ + tf->protocol = ATA_PROT_NCQ; + tf->command = ATA_CMD_FPDMA_SEND; + tf->hob_nsect = ATA_SUBCMD_FPDMA_SEND_DSM & 0x1f; + tf->nsect = qc->tag << 3; + tf->hob_feature = (size / 512) >> 8; + tf->feature = size / 512; + + tf->auxiliary = 1; + } else { + tf->protocol = ATA_PROT_DMA; + tf->hob_feature = 0; + tf->feature = ATA_DSM_TRIM; + tf->hob_nsect = (size / 512) >> 8; + tf->nsect = size / 512; + tf->command = ATA_CMD_DSM; + } } tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f459dff..b5ffcd3 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -794,7 +794,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; } diff --git a/include/linux/ata.h b/include/linux/ata.h index 99346be..4132de3 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 * 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 */