From patchwork Fri Dec 10 15:01:33 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Hellwig X-Patchwork-Id: 75105 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 3D038B7043 for ; Sat, 11 Dec 2010 02:20:02 +1100 (EST) Received: from localhost ([127.0.0.1]:45931 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PR4lK-00048H-6z for incoming@patchwork.ozlabs.org; Fri, 10 Dec 2010 10:19:58 -0500 Received: from [140.186.70.92] (port=47584 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PR4TY-0001VU-0J for qemu-devel@nongnu.org; Fri, 10 Dec 2010 10:01:37 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PR4TW-0003rz-Cy for qemu-devel@nongnu.org; Fri, 10 Dec 2010 10:01:35 -0500 Received: from verein.lst.de ([213.95.11.210]:55205) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PR4TV-0003rf-U8 for qemu-devel@nongnu.org; Fri, 10 Dec 2010 10:01:34 -0500 Received: from verein.lst.de (localhost [127.0.0.1]) by verein.lst.de (8.12.3/8.12.3/Debian-7.1) with ESMTP id oBAF1X88031192 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO) for ; Fri, 10 Dec 2010 16:01:33 +0100 Received: (from hch@localhost) by verein.lst.de (8.12.3/8.12.3/Debian-7.2) id oBAF1XCc031191 for qemu-devel@nongnu.org; Fri, 10 Dec 2010 16:01:33 +0100 Date: Fri, 10 Dec 2010 16:01:33 +0100 From: Christoph Hellwig To: qemu-devel@nongnu.org Message-ID: <20101210150133.GF31114@lst.de> References: <20101210150038.GA30990@lst.de> Mime-Version: 1.0 Content-Disposition: inline In-Reply-To: <20101210150038.GA30990@lst.de> User-Agent: Mutt/1.3.28i X-Scanned-By: MIMEDefang 2.39 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Subject: [Qemu-devel] [PATCH 6/7] ide: add TRIM support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add support for the data set management command, and the TRIM sub function in it. Signed-off-by: Christoph Hellwig Index: qemu/hw/ide/core.c =================================================================== --- qemu.orig/hw/ide/core.c 2010-12-10 11:35:30.471253949 +0100 +++ qemu/hw/ide/core.c 2010-12-10 11:35:33.430253739 +0100 @@ -146,6 +146,9 @@ static void ide_identify(IDEState *s) put_le16(p + 66, 120); put_le16(p + 67, 120); put_le16(p + 68, 120); + if (dev && dev->conf.discard_granularity) { + put_le16(p + 69, (1 << 14)); /* determinate TRIM behavior */ + } put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */ put_le16(p + 81, 0x16); /* conforms to ata5 */ /* 14=NOP supported, 5=WCACHE supported, 0=SMART supported */ @@ -172,6 +175,9 @@ static void ide_identify(IDEState *s) dev = s->unit ? s->bus->slave : s->bus->master; if (dev && dev->conf.physical_block_size) put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf)); + if (dev && dev->conf.discard_granularity) { + put_le16(p + 169, 1); /* TRIM support */ + } memcpy(s->identify_data, p, sizeof(s->identify_data)); s->identify_set = 1; @@ -1746,6 +1752,72 @@ static void ide_clear_hob(IDEBus *bus) bus->ifs[1].select &= ~(1 << 7); } +typedef struct TrimAIOCB { + BlockDriverAIOCB common; + QEMUBH *bh; + int ret; +} TrimAIOCB; + +static void trim_aio_cancel(BlockDriverAIOCB *acb) +{ + TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common); + + qemu_bh_delete(iocb->bh); + iocb->bh = NULL; + qemu_aio_release(iocb); +} + +static AIOPool trim_aio_pool = { + .aiocb_size = sizeof(TrimAIOCB), + .cancel = trim_aio_cancel, +}; + +static void ide_trim_bh_cb(void *opaque) +{ + TrimAIOCB *iocb = opaque; + + iocb->common.cb(iocb->common.opaque, iocb->ret); + + qemu_bh_delete(iocb->bh); + iocb->bh = NULL; + + qemu_aio_release(iocb); +} + +static BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + TrimAIOCB *iocb; + int i, j, ret; + + iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque); + iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); + iocb->ret = 0; + + for (j = 0; j < qiov->niov; j++) { + uint64_t *buffer = qiov->iov[j].iov_base; + + for (i = 0; i < qiov->iov[j].iov_len / 8; i++) { + /* 6-byte LBA + 2-byte range per entry */ + uint64_t entry = le64_to_cpu(buffer[i]); + uint64_t sector = entry & 0x0000ffffffffffffULL; + uint16_t count = entry >> 48; + + if (count == 0) + break; + + ret = bdrv_discard(bs, sector * 512, count * 512); + if (!iocb->ret) + iocb->ret = ret; + } + } + + qemu_bh_schedule(iocb->bh); + + return &iocb->common; +} + void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) { IDEBus *bus = opaque; @@ -1825,6 +1897,17 @@ void ide_ioport_write(void *opaque, uint break; switch(val) { + case WIN_DSM: + switch (s->feature) { + case DSM_TRIM: + if (!s->bs) + goto abort_cmd; + ide_sector_dma(s, ide_issue_trim, 0); + break; + default: + goto abort_cmd; + } + break; case WIN_IDENTIFY: if (s->bs && s->drive_kind != IDE_CD) { if (s->drive_kind != IDE_CFATA) Index: qemu/hw/ide/internal.h =================================================================== --- qemu.orig/hw/ide/internal.h 2010-12-10 11:33:41.444006150 +0100 +++ qemu/hw/ide/internal.h 2010-12-10 11:35:33.446003914 +0100 @@ -60,7 +60,11 @@ typedef struct BMDMAState BMDMAState; */ #define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ /* - * 0x04->0x07 Reserved + * 0x04->0x05 Reserved + */ +#define WIN_DSM 0x06 +/* + * 0x07 Reserved */ #define WIN_SRST 0x08 /* ATAPI soft reset command */ #define WIN_DEVICE_RESET 0x08 @@ -188,6 +192,9 @@ typedef struct BMDMAState BMDMAState; #define IDE_DMA_BUF_SECTORS 256 +/* feature values for Data Set Management */ +#define DSM_TRIM 0x01 + #if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS) #error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS" #endif Index: qemu/hw/ide/qdev.c =================================================================== --- qemu.orig/hw/ide/qdev.c 2010-12-10 11:24:19.324253880 +0100 +++ qemu/hw/ide/qdev.c 2010-12-10 11:35:33.450257860 +0100 @@ -110,6 +110,11 @@ static int ide_drive_initfn(IDEDevice *d const char *serial; DriveInfo *dinfo; + if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) { + error_report("discard_granularity must be 512 for ide"); + return -1; + } + serial = dev->serial; if (!serial) { /* try to fall back to value set with legacy -drive serial=... */