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
next prev 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).