linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Mark Lord <liml@rtr.ca>
To: Christoph Hellwig <hch@infradead.org>
Cc: Jeff Garzik <jgarzik@pobox.com>,
	linux-ide@vger.kernel.org, linux-scsi@vger.kernel.org,
	"Martin K. Petersen" <mkp@mkp.net>, Matthew Wilcox <willy@wil.cx>
Subject: Re: [PATCH] libata: add TRIM support
Date: Tue, 17 Nov 2009 09:04:54 -0500	[thread overview]
Message-ID: <4B02AD86.8010304@rtr.ca> (raw)
In-Reply-To: <20091116154343.GA6672@infradead.org>

Christoph Hellwig wrote:
> Add support for the ATA TRIM command in libata.  We translate a WRITE SAME 16
> command with the unmap bit set into an ATA TRIM command and export enough
> information in READ CAPACITY 16 and the block limits EVPD page so that the new
> SCSI layer discard support will driver this for us.
> 
> Note that I hardcode the WRITE_SAME_16 opcode for now as the patch to introduce
> the symbolic is not in 2.6.32 yet but only in the SCSI tree - as soon as it is
> merged we can fix it up to properly use the symbolic name.
> 
> Tested with a OCZ Vertex SSD and my still quite hackish TRIM emulation
> for qemu.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> 
> Index: linux-2.6/drivers/ata/libata-scsi.c
> ===================================================================
> --- linux-2.6.orig/drivers/ata/libata-scsi.c	2009-11-16 16:37:37.776003870 +0100
> +++ linux-2.6/drivers/ata/libata-scsi.c	2009-11-16 16:37:41.864004223 +0100
> @@ -47,6 +47,7 @@
>  #include <linux/hdreg.h>
>  #include <linux/uaccess.h>
>  #include <linux/suspend.h>
> +#include <asm/unaligned.h>
>  
>  #include "libata.h"
>  
> @@ -1964,6 +1965,7 @@ static unsigned int ata_scsiop_inq_00(st
>  		0x80,	/* page 0x80, unit serial no page */
>  		0x83,	/* page 0x83, device ident page */
>  		0x89,	/* page 0x89, ata info page */
> +		0xb0,	/* page 0xb0, block limits page */
>  		0xb1,	/* page 0xb1, block device characteristics page */
>  	};
>  
> @@ -2085,6 +2087,40 @@ static unsigned int ata_scsiop_inq_89(st
>  	return 0;
>  }
>  
> +static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
> +{
> +	u32 min_io_sectors;
> +
> +	rbuf[1] = 0xb0;
> +	rbuf[3] = 0x3c;		/* required VPD size with unmap support */
> +
> +	/*
> +	 * Optimal transfer length granularity.
> +	 *
> +	 * This is always one physical block, but for disks with a smaller
> +	 * logical than physical sector size we need to figure out what the
> +	 * latter is.
> +	 */
> +	min_io_sectors = 1;
> +	if ((args->id[106] & 0xc000) == 0x4000 && (args->id[106] & (1 << 13)))
> +		min_io_sectors *= args->id[106] & 0xf;
> +	put_unaligned_be16(min_io_sectors, &rbuf[6]);
> +
> +	/*
> +	 * Optimal unmap granularity.
> +	 *
> +	 * The ATA spec doesn't even know about a granularity or alignment
> +	 * for the TRIM command.  We can leave away most of the unmap related
> +	 * VPD page entries, but we have specifify a granularity to signal
> +	 * that we support some form of unmap - in thise case via WRITE SAME
> +	 * with the unmap bit set.
> +	 */
> +	if (ata_id_has_trim(args->id))
> +		put_unaligned_be32(1, &rbuf[28]);
> +
> +	return 0;
> +}
> +
>  static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf)
>  {
>  	int form_factor = ata_id_form_factor(args->id);
> @@ -2374,6 +2410,9 @@ static unsigned int ata_scsiop_read_cap(
>  		rbuf[13] = log_per_phys;
>  		rbuf[14] = (lowest_aligned >> 8) & 0x3f;
>  		rbuf[15] = lowest_aligned;
> +
> +		if (ata_id_has_trim(args->id))
> +			rbuf[14] |= 0x80;
>  	}
>  
>  	return 0;
> @@ -2896,6 +2935,70 @@ static unsigned int ata_scsi_pass_thru(s
>  	return 1;
>  }
>  
> +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;
> +	const u8 *cdb = scmd->cmnd;
> +	u64 block;
> +	u32 n_block;
> +	u32 size;
> +	void *buf;
> +
> +	/* we may not issue DMA commands if no DMA mode is set */
> +	if (unlikely(!dev->dma_mode))
> +		goto invalid_fld;
> +
> +	if (unlikely(scmd->cmd_len < 16))
> +		goto invalid_fld;
> +	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)))
> +		goto invalid_fld;
> +
> +	/*
> +	 * WRITE SAME always has a sector sized buffer as payload, this
> +	 * should never be a multiple entry S/G list.
> +	 */
> +	if (!scsi_sg_count(scmd))
> +		goto invalid_fld;
> +
> +	buf = page_address(sg_page(scsi_sglist(scmd)));
> +	size = ata_set_lba_range_entries(buf, 512 / 8, block, n_block);
> +
> +	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->hob_lbal = 0;
> +	tf->lbal = 0;
> +	tf->hob_lbam = 0;
> +	tf->lbam = 0;
> +	tf->hob_lbah = 0;
> +	tf->lbah = 0;
> +	tf->device = ATA_LBA;
> +	tf->command = ATA_CMD_DSM;
> +	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 |
> +		     ATA_TFLAG_WRITE;
> +	tf->device = dev->devno ?
> +		tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
> +
> +	qc->sect_size = ATA_SECT_SIZE;
> +	qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET;
> +
> +	ata_qc_set_pc_nbytes(qc);
> +
> +	return 0;
> +
> + invalid_fld:
> +	ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00);
> +	/* "Invalid field in cdb" */
> +	return 1;
> +}
> +
>  /**
>   *	ata_get_xlat_func - check if SCSI to ATA translation is possible
>   *	@dev: ATA device
> @@ -2920,6 +3023,9 @@ static inline ata_xlat_func_t ata_get_xl
>  	case WRITE_16:
>  		return ata_scsi_rw_xlat;
>  
> +	case 0x93 /*WRITE_SAME_16*/:
> +		return ata_scsi_write_same_xlat;
> +
>  	case SYNCHRONIZE_CACHE:
>  		if (ata_try_flush_cache(dev))
>  			return ata_scsi_flush_xlat;
> @@ -3109,6 +3215,9 @@ void ata_scsi_simulate(struct ata_device
>  		case 0x89:
>  			ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
>  			break;
> +		case 0xb0:
> +			ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b0);
> +			break;
>  		case 0xb1:
>  			ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1);
>  			break;
..

Where is the code that sets up the multi-entry trim list
that this command requires as data?  It's probably there,
but I don't see it (blind or something).

And, where is the per-ATA-host flag to enable use of this feature,
with the default being DISABLED.  Or vice versa, if you want to test
all the supported controllers first for compatibility.

Eg. sata_mv, sata_sil, .. won't work as-is with this command.

Thanks

Mark

  parent reply	other threads:[~2009-11-17 14:04 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-11-16 15:43 [PATCH] libata: add TRIM support Christoph Hellwig
2009-11-16 16:07 ` Alan Cox
2009-11-16 16:19   ` Sergei Shtylyov
2009-11-17 14:30   ` Christoph Hellwig
2009-11-17  3:34 ` Jeff Garzik
2009-11-17 14:32   ` Christoph Hellwig
2009-11-17 21:59     ` Jeff Garzik
2009-11-17 14:36   ` Christoph Hellwig
2009-11-17 14:04 ` Mark Lord [this message]
2009-11-17 14:35   ` Christoph Hellwig
2009-11-17 14:52     ` Alan Cox
2009-11-17 15:00       ` Christoph Hellwig
2009-11-19  3:35         ` Mark Lord
2009-11-19 10:23           ` Alan Cox
2009-11-19 14:22             ` Mark Lord
     [not found]               ` <4B05DE00.3020707@gmail.com>
     [not found]                 ` <20091120001829.354abfc0@lxorguk.ukuu.org.uk>
     [not found]                   ` <4B05E3D1.1000904@pobox.com>
2009-11-20 12:46                     ` Alan Cox
2009-11-21  4:33                       ` Mark Lord
2009-11-21  6:09                         ` Martin K. Petersen
2009-11-22  2:39                           ` Mark Lord

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B02AD86.8010304@rtr.ca \
    --to=liml@rtr.ca \
    --cc=hch@infradead.org \
    --cc=jgarzik@pobox.com \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=mkp@mkp.net \
    --cc=willy@wil.cx \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).