From: Kevin Wolf <kwolf@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, hch@lst.de
Subject: [Qemu-devel] [PATCH v2 3/3] ide: add TRIM support
Date: Tue, 14 Jun 2011 17:54:53 +0200 [thread overview]
Message-ID: <1308066893-20701-1-git-send-email-kwolf@redhat.com> (raw)
In-Reply-To: <20110519085819.GC3679@lst.de>
From: Christoph Hellwig <hch@lst.de>
Add support for TRIM sub function of the data set management command,
and wire it up to the qemu discard infrastructure.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
v2:
- Fixed bdrv_discard call (takes sectors, not bytes)
- Fixed TRIM restart after failure
- Fixed use of uninitialised variable
- Fixed coding style
---
hw/ide/core.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++-
hw/ide/internal.h | 14 +++++++-
hw/ide/macio.c | 4 ++
hw/ide/pci.c | 9 ++++-
hw/ide/qdev.c | 5 +++
5 files changed, 124 insertions(+), 5 deletions(-)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 14bda82..ca17a43 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -78,7 +78,7 @@ static void ide_identify(IDEState *s)
{
uint16_t *p;
unsigned int oldsize;
- IDEDevice *dev;
+ IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
if (s->identify_set) {
memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
@@ -124,6 +124,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 */
+ }
if (s->ncq_queues) {
put_le16(p + 75, s->ncq_queues - 1);
@@ -154,9 +157,12 @@ static void ide_identify(IDEState *s)
put_le16(p + 101, s->nb_sectors >> 16);
put_le16(p + 102, s->nb_sectors >> 32);
put_le16(p + 103, s->nb_sectors >> 48);
- 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;
@@ -299,6 +305,74 @@ static void ide_set_signature(IDEState *s)
}
}
+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);
+}
+
+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, count);
+ if (!iocb->ret) {
+ iocb->ret = ret;
+ }
+ }
+ }
+
+ qemu_bh_schedule(iocb->bh);
+
+ return &iocb->common;
+}
+
static inline void ide_abort_command(IDEState *s)
{
s->status = READY_STAT | ERR_STAT;
@@ -474,6 +548,9 @@ handle_rw_error:
if (s->dma_cmd == IDE_DMA_READ)
op |= BM_STATUS_RETRY_READ;
+ else if (s->dma_cmd == IDE_DMA_TRIM)
+ op |= BM_STATUS_RETRY_TRIM;
+
if (ide_handle_rw_error(s, -ret, op)) {
return;
}
@@ -519,6 +596,10 @@ handle_rw_error:
s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
ide_dma_cb, s);
break;
+ case IDE_DMA_TRIM:
+ s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+ ide_issue_trim, ide_dma_cb, s, 1);
+ break;
}
if (!s->bus->dma->aiocb) {
@@ -818,6 +899,18 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
return;
switch(val) {
+ case WIN_DSM:
+ switch (s->feature) {
+ case DSM_TRIM:
+ if (!s->bs) {
+ goto abort_cmd;
+ }
+ ide_sector_start_dma(s, IDE_DMA_TRIM);
+ break;
+ default:
+ goto abort_cmd;
+ }
+ break;
case WIN_IDENTIFY:
if (s->bs && s->drive_kind != IDE_CD) {
if (s->drive_kind != IDE_CFATA)
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index ea3edf5..02e805f 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -62,7 +62,11 @@ typedef struct IDEDMAOps IDEDMAOps;
*/
#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
@@ -190,6 +194,9 @@ typedef struct IDEDMAOps IDEDMAOps;
#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
@@ -382,6 +389,7 @@ struct unreported_events {
enum ide_dma_cmd {
IDE_DMA_READ,
IDE_DMA_WRITE,
+ IDE_DMA_TRIM,
};
#define ide_cmd_is_read(s) \
@@ -521,6 +529,7 @@ struct IDEDeviceInfo {
#define BM_STATUS_PIO_RETRY 0x10
#define BM_STATUS_RETRY_READ 0x20
#define BM_STATUS_RETRY_FLUSH 0x40
+#define BM_STATUS_RETRY_TRIM 0x80
#define BM_MIGRATION_COMPAT_STATUS_BITS \
(BM_STATUS_DMA_RETRY | BM_STATUS_PIO_RETRY | \
@@ -591,6 +600,9 @@ void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func);
void ide_transfer_stop(IDEState *s);
void ide_set_inactive(IDEState *s);
+BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
/* hw/ide/atapi.c */
void ide_atapi_cmd(IDEState *s);
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 099b8cb..7daeb31 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -154,6 +154,10 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
pmac_ide_transfer_cb, io);
break;
+ case IDE_DMA_TRIM:
+ m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+ ide_issue_trim, pmac_ide_transfer_cb, s, 1);
+ break;
}
if (!m->aiocb)
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 80c5794..c940375 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -200,8 +200,13 @@ static void bmdma_restart_bh(void *opaque)
is_read = !!(bus->error_status & BM_STATUS_RETRY_READ);
if (bus->error_status & BM_STATUS_DMA_RETRY) {
- bus->error_status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
- bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
+ if (bus->error_status & BM_STATUS_RETRY_TRIM) {
+ bus->error_status &= ~BM_STATUS_RETRY_TRIM;
+ bmdma_restart_dma(bm, IDE_DMA_TRIM);
+ } else {
+ bus->error_status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
+ bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
+ }
} else if (bus->error_status & BM_STATUS_PIO_RETRY) {
bus->error_status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
if (is_read) {
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 3f9dc89..d9b8f24 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -125,6 +125,11 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
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=... */
--
1.7.5.2
next prev parent reply other threads:[~2011-06-14 15:52 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-05-19 8:57 [Qemu-devel] [PATCH 0/3] ide: add TRIM support Christoph Hellwig
2011-05-19 8:57 ` [Qemu-devel] [PATCH 1/3] make dma_bdrv_io available to drivers Christoph Hellwig
2011-05-19 8:58 ` [Qemu-devel] [PATCH 2/3] ide: allow other dma comands than read and write Christoph Hellwig
2011-05-19 8:58 ` [Qemu-devel] [PATCH 3/3] ide: add TRIM support Christoph Hellwig
2011-06-10 11:47 ` Kevin Wolf
2011-06-10 14:04 ` Kevin Wolf
2011-06-14 15:54 ` Kevin Wolf [this message]
2011-06-07 11:13 ` [Qemu-devel] [PATCH 0/3] " Christoph Hellwig
2011-06-07 14:11 ` Kevin Wolf
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=1308066893-20701-1-git-send-email-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=hch@lst.de \
--cc=qemu-devel@nongnu.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.