*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/blockdev.h"
#include "sysemu/dma.h"
#include "hw/block/block.h"
#include "sysemu/block-backend.h"
#include "qemu/cutils.h"
-#include "qemu/error-report.h"
#include "hw/ide/internal.h"
#include "trace.h"
static const char *IDE_DMA_CMD_str(enum ide_dma_cmd enval)
{
- if (enval >= IDE_DMA__BEGIN && enval < IDE_DMA__COUNT) {
+ if ((unsigned)enval < IDE_DMA__COUNT) {
return IDE_DMA_CMD_lookup[enval];
}
return "DMA UNKNOWN CMD";
if (dev && dev->conf.discard_granularity) {
put_le16(p + 169, 1); /* TRIM support */
}
+ if (dev) {
+ put_le16(p + 217, dev->rotation_rate); /* Nominal media rotation rate */
+ }
ide_identify_size(s);
s->identify_set = 1;
}
}
+static bool ide_sect_range_ok(IDEState *s,
+ uint64_t sector, uint64_t nb_sectors)
+{
+ uint64_t total_sectors;
+
+ blk_get_geometry(s->blk, &total_sectors);
+ if (sector > total_sectors || nb_sectors > total_sectors - sector) {
+ return false;
+ }
+ return true;
+}
+
typedef struct TrimAIOCB {
BlockAIOCB common;
- BlockBackend *blk;
+ IDEState *s;
QEMUBH *bh;
int ret;
QEMUIOVector *qiov;
BlockAIOCB *aiocb;
int i, j;
+ bool is_invalid;
} TrimAIOCB;
static void trim_aio_cancel(BlockAIOCB *acb)
{
TrimAIOCB *iocb = opaque;
- iocb->common.cb(iocb->common.opaque, iocb->ret);
-
+ if (iocb->is_invalid) {
+ ide_dma_error(iocb->s);
+ } else {
+ iocb->common.cb(iocb->common.opaque, iocb->ret);
+ }
qemu_bh_delete(iocb->bh);
iocb->bh = NULL;
qemu_aio_unref(iocb);
static void ide_issue_trim_cb(void *opaque, int ret)
{
TrimAIOCB *iocb = opaque;
+ IDEState *s = iocb->s;
+
if (ret >= 0) {
while (iocb->j < iocb->qiov->niov) {
int j = iocb->j;
continue;
}
+ if (!ide_sect_range_ok(s, sector, count)) {
+ iocb->is_invalid = true;
+ goto done;
+ }
+
/* Got an entry! Submit and exit. */
- iocb->aiocb = blk_aio_pdiscard(iocb->blk,
+ iocb->aiocb = blk_aio_pdiscard(s->blk,
sector << BDRV_SECTOR_BITS,
count << BDRV_SECTOR_BITS,
ide_issue_trim_cb, opaque);
iocb->ret = ret;
}
+done:
iocb->aiocb = NULL;
if (iocb->bh) {
qemu_bh_schedule(iocb->bh);
int64_t offset, QEMUIOVector *qiov,
BlockCompletionFunc *cb, void *cb_opaque, void *opaque)
{
- BlockBackend *blk = opaque;
+ IDEState *s = opaque;
TrimAIOCB *iocb;
- iocb = blk_aio_get(&trim_aiocb_info, blk, cb, cb_opaque);
- iocb->blk = blk;
+ iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque);
+ iocb->s = s;
iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb);
iocb->ret = 0;
iocb->qiov = qiov;
iocb->i = -1;
iocb->j = 0;
+ iocb->is_invalid = false;
ide_issue_trim_cb(iocb, 0);
return &iocb->common;
}
ide_set_irq(s->bus);
}
-static bool ide_sect_range_ok(IDEState *s,
- uint64_t sector, uint64_t nb_sectors)
-{
- uint64_t total_sectors;
-
- blk_get_geometry(s->blk, &total_sectors);
- if (sector > total_sectors || nb_sectors > total_sectors - sector) {
- return false;
- }
- return true;
-}
-
static void ide_buffered_readv_cb(void *opaque, int ret)
{
IDEBufferedRequest *req = opaque;
case IDE_DMA_TRIM:
s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk),
&s->sg, offset, BDRV_SECTOR_SIZE,
- ide_issue_trim, s->blk, ide_dma_cb, s,
+ ide_issue_trim, s, ide_dma_cb, s,
DMA_DIRECTION_TO_DEVICE);
break;
default:
return 0;
}
-static void ide_drive_pio_pre_save(void *opaque)
+static int ide_drive_pio_pre_save(void *opaque)
{
IDEState *s = opaque;
int idx;
} else {
s->end_transfer_fn_idx = idx;
}
+
+ return 0;
}
static bool ide_drive_pio_state_needed(void *opaque)