*/
#include <hw/hw.h>
#include <hw/pc.h>
-#include <hw/pci.h>
+#include <hw/pci/pci.h>
#include <hw/isa.h>
-#include "qemu-error.h"
-#include "qemu-timer.h"
-#include "sysemu.h"
-#include "dma.h"
-#include "blockdev.h"
-#include "block_int.h"
+#include "qemu/error-report.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
+#include "hw/block-common.h"
+#include "sysemu/blockdev.h"
#include <hw/ide/internal.h>
{ 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
/* airflow-temperature-celsius */
{ 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
- /* end of list */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
static int ide_handle_rw_error(IDEState *s, int error, int op);
put_le16(p + 21, 512); /* cache size in sectors */
put_le16(p + 22, 4); /* ecc bytes */
padstr((char *)(p + 23), s->version, 8); /* firmware version */
- padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
+ padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
#if MAX_MULT_SECTORS > 1
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
#endif
put_le16(p + 82, (1 << 14) | (1 << 5) | 1);
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
- /* 14=set to 1, 1=SMART self test, 0=SMART error logging */
- put_le16(p + 84, (1 << 14) | 0);
+ /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
+ if (s->wwn) {
+ put_le16(p + 84, (1 << 14) | (1 << 8) | 0);
+ } else {
+ put_le16(p + 84, (1 << 14) | 0);
+ }
/* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
if (bdrv_enable_write_cache(s->bs))
put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
else
put_le16(p + 85, (1 << 14) | 1);
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
- put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
- /* 14=set to 1, 1=smart self test, 0=smart error logging */
- put_le16(p + 87, (1 << 14) | 0);
+ put_le16(p + 86, (1 << 13) | (1 <<12) | (1 << 10));
+ /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
+ if (s->wwn) {
+ put_le16(p + 87, (1 << 14) | (1 << 8) | 0);
+ } else {
+ put_le16(p + 87, (1 << 14) | 0);
+ }
put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
put_le16(p + 93, 1 | (1 << 14) | 0x2000);
put_le16(p + 100, s->nb_sectors);
if (dev && dev->conf.physical_block_size)
put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
+ if (s->wwn) {
+ /* LE 16-bit words 111-108 contain 64-bit World Wide Name */
+ put_le16(p + 108, s->wwn >> 48);
+ put_le16(p + 109, s->wwn >> 32);
+ put_le16(p + 110, s->wwn >> 16);
+ put_le16(p + 111, s->wwn);
+ }
if (dev && dev->conf.discard_granularity) {
put_le16(p + 169, 1); /* TRIM support */
}
put_le16(p + 21, 512); /* cache size in sectors */
put_le16(p + 22, 4); /* ecc bytes */
padstr((char *)(p + 23), s->version, 8); /* firmware version */
- padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */
+ padstr((char *)(p + 27), s->drive_model_str, 40); /* model */
put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
#ifdef USE_DMA_CDROM
put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
put_le16(p + 22, 0x0004); /* ECC bytes */
padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */
- padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
+ padstr((char *) (p + 27), s->drive_model_str, 40);/* Model number */
#if MAX_MULT_SECTORS > 1
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
#else
BlockDriverAIOCB common;
QEMUBH *bh;
int ret;
+ QEMUIOVector *qiov;
+ BlockDriverAIOCB *aiocb;
+ int i, j;
} TrimAIOCB;
static void trim_aio_cancel(BlockDriverAIOCB *acb)
{
TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
+ /* Exit the loop in case bdrv_aio_cancel calls ide_issue_trim_cb again. */
+ iocb->j = iocb->qiov->niov - 1;
+ iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1;
+
+ /* Tell ide_issue_trim_cb not to trigger the completion, too. */
qemu_bh_delete(iocb->bh);
iocb->bh = NULL;
+
+ if (iocb->aiocb) {
+ bdrv_aio_cancel(iocb->aiocb);
+ }
qemu_aio_release(iocb);
}
-static AIOPool trim_aio_pool = {
+static const AIOCBInfo trim_aiocb_info = {
.aiocb_size = sizeof(TrimAIOCB),
.cancel = trim_aio_cancel,
};
qemu_bh_delete(iocb->bh);
iocb->bh = NULL;
-
qemu_aio_release(iocb);
}
+static void ide_issue_trim_cb(void *opaque, int ret)
+{
+ TrimAIOCB *iocb = opaque;
+ if (ret >= 0) {
+ while (iocb->j < iocb->qiov->niov) {
+ int j = iocb->j;
+ while (++iocb->i < iocb->qiov->iov[j].iov_len / 8) {
+ int i = iocb->i;
+ uint64_t *buffer = iocb->qiov->iov[j].iov_base;
+
+ /* 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) {
+ continue;
+ }
+
+ /* Got an entry! Submit and exit. */
+ iocb->aiocb = bdrv_aio_discard(iocb->common.bs, sector, count,
+ ide_issue_trim_cb, opaque);
+ return;
+ }
+
+ iocb->j++;
+ iocb->i = -1;
+ }
+ } else {
+ iocb->ret = ret;
+ }
+
+ iocb->aiocb = NULL;
+ if (iocb->bh) {
+ qemu_bh_schedule(iocb->bh);
+ }
+}
+
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 = qemu_aio_get(&trim_aiocb_info, 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);
-
+ iocb->qiov = qiov;
+ iocb->i = -1;
+ iocb->j = 0;
+ ide_issue_trim_cb(iocb, 0);
return &iocb->common;
}
ide_set_irq(s->bus);
}
+static void ide_sector_read_cb(void *opaque, int ret)
+{
+ IDEState *s = opaque;
+ int n;
+
+ s->pio_aiocb = NULL;
+ s->status &= ~BUSY_STAT;
+
+ bdrv_acct_done(s->bs, &s->acct);
+ if (ret != 0) {
+ if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY |
+ BM_STATUS_RETRY_READ)) {
+ return;
+ }
+ }
+
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
+ /* Allow the guest to read the io_buffer */
+ ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
+
+ ide_set_irq(s->bus);
+
+ ide_set_sector(s, ide_get_sector(s) + n);
+ s->nsector -= n;
+}
+
void ide_sector_read(IDEState *s)
{
int64_t sector_num;
- int ret, n;
+ int n;
s->status = READY_STAT | SEEK_STAT;
s->error = 0; /* not needed by IDE spec, but needed by Windows */
sector_num = ide_get_sector(s);
n = s->nsector;
+
if (n == 0) {
- /* no more sector to read from disk */
ide_transfer_stop(s);
- } else {
+ return;
+ }
+
+ s->status |= BUSY_STAT;
+
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
#if defined(DEBUG_IDE)
- printf("read sector=%" PRId64 "\n", sector_num);
+ printf("sector=%" PRId64 "\n", sector_num);
#endif
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
- bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
- bdrv_acct_done(s->bs, &s->acct);
- if (ret != 0) {
- if (ide_handle_rw_error(s, -ret,
- BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
- {
- return;
- }
- }
- ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
- ide_set_irq(s->bus);
- ide_set_sector(s, sector_num + n);
- s->nsector -= n;
- }
+ s->iov.iov_base = s->io_buffer;
+ s->iov.iov_len = n * BDRV_SECTOR_SIZE;
+ qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+ bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ s->pio_aiocb = bdrv_aio_readv(s->bs, sector_num, &s->qiov, n,
+ ide_sector_read_cb, s);
}
static void dma_buf_commit(IDEState *s)
static int ide_handle_rw_error(IDEState *s, int error, int op)
{
- int is_read = (op & BM_STATUS_RETRY_READ);
- BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
+ bool is_read = (op & BM_STATUS_RETRY_READ) != 0;
+ BlockErrorAction action = bdrv_get_error_action(s->bs, is_read, error);
- if (action == BLOCK_ERR_IGNORE) {
- bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_IGNORE, is_read);
- return 0;
- }
-
- if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
- || action == BLOCK_ERR_STOP_ANY) {
+ if (action == BDRV_ACTION_STOP) {
s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
s->bus->error_status = op;
- bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_STOP, is_read);
- vm_stop(RUN_STATE_IO_ERROR);
- bdrv_iostatus_set_err(s->bs, error);
- } else {
+ } else if (action == BDRV_ACTION_REPORT) {
if (op & BM_STATUS_DMA_RETRY) {
dma_buf_commit(s);
ide_dma_error(s);
} else {
ide_rw_error(s);
}
- bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_REPORT, is_read);
}
-
- return 1;
+ bdrv_error_action(s->bs, action, is_read, error);
+ return action != BDRV_ACTION_IGNORE;
}
void ide_dma_cb(void *opaque, int ret)
IDEState *s = opaque;
int n;
int64_t sector_num;
+ bool stay_active = false;
if (ret < 0) {
int op = BM_STATUS_DMA_RETRY;
}
n = s->io_buffer_size >> 9;
+ if (n > s->nsector) {
+ /* The PRDs were longer than needed for this request. Shorten them so
+ * we don't get a negative remainder. The Active bit must remain set
+ * after the request completes. */
+ n = s->nsector;
+ stay_active = true;
+ }
+
sector_num = ide_get_sector(s);
if (n > 0) {
dma_buf_commit(s);
if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) {
/* The PRDs were too short. Reset the Active bit, but don't raise an
* interrupt. */
+ s->status = READY_STAT | SEEK_STAT;
goto eot;
}
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, true);
+ ide_issue_trim, ide_dma_cb, s,
+ DMA_DIRECTION_TO_DEVICE);
break;
}
return;
bdrv_acct_done(s->bs, &s->acct);
}
ide_set_inactive(s);
+ if (stay_active) {
+ s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_DMAING);
+ }
}
static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
ide_set_irq(s->bus);
}
-void ide_sector_write(IDEState *s)
+static void ide_sector_write_cb(void *opaque, int ret)
{
- int64_t sector_num;
- int ret, n, n1;
-
- s->status = READY_STAT | SEEK_STAT;
- sector_num = ide_get_sector(s);
-#if defined(DEBUG_IDE)
- printf("write sector=%" PRId64 "\n", sector_num);
-#endif
- n = s->nsector;
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
+ IDEState *s = opaque;
+ int n;
- bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
bdrv_acct_done(s->bs, &s->acct);
+ s->pio_aiocb = NULL;
+ s->status &= ~BUSY_STAT;
+
if (ret != 0) {
- if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
+ if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY)) {
return;
+ }
}
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
s->nsector -= n;
if (s->nsector == 0) {
/* no more sectors to write */
ide_transfer_stop(s);
} else {
- n1 = s->nsector;
- if (n1 > s->req_nb_sectors)
+ int n1 = s->nsector;
+ if (n1 > s->req_nb_sectors) {
n1 = s->req_nb_sectors;
- ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
+ }
+ ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE,
+ ide_sector_write);
}
- ide_set_sector(s, sector_num + n);
+ ide_set_sector(s, ide_get_sector(s) + n);
if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
/* It seems there is a bug in the Windows 2000 installer HDD
}
}
+void ide_sector_write(IDEState *s)
+{
+ int64_t sector_num;
+ int n;
+
+ s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
+ sector_num = ide_get_sector(s);
+#if defined(DEBUG_IDE)
+ printf("sector=%" PRId64 "\n", sector_num);
+#endif
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
+ s->iov.iov_base = s->io_buffer;
+ s->iov.iov_len = n * BDRV_SECTOR_SIZE;
+ qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+ bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ s->pio_aiocb = bdrv_aio_writev(s->bs, sector_num, &s->qiov, n,
+ ide_sector_write_cb, s);
+}
+
static void ide_flush_cb(void *opaque, int ret)
{
IDEState *s = opaque;
[WIN_IDENTIFY] = ALL_OK,
[WIN_SETFEATURES] = ALL_OK,
[IBM_SENSE_CONDITION] = CFA_OK,
- [CFA_WEAR_LEVEL] = CFA_OK,
+ [CFA_WEAR_LEVEL] = HD_CFA_OK,
[WIN_READ_NATIVE_MAX] = ALL_OK,
};
void ide_exec_cmd(IDEBus *bus, uint32_t val)
{
+ uint16_t *identify_data;
IDEState *s;
int n;
int lba48 = 0;
ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */
goto abort_cmd;
}
+ if (!s->bs) {
+ goto abort_cmd;
+ }
ide_cmd_lba48_transform(s, lba48);
s->req_nb_sectors = 1;
ide_sector_read(s);
case WIN_WRITE_ONCE:
case CFA_WRITE_SECT_WO_ERASE:
case WIN_WRITE_VERIFY:
+ if (!s->bs) {
+ goto abort_cmd;
+ }
ide_cmd_lba48_transform(s, lba48);
s->error = 0;
s->status = SEEK_STAT | READY_STAT;
case WIN_MULTREAD_EXT:
lba48 = 1;
case WIN_MULTREAD:
- if (!s->mult_sectors)
+ if (!s->bs) {
goto abort_cmd;
+ }
+ if (!s->mult_sectors) {
+ goto abort_cmd;
+ }
ide_cmd_lba48_transform(s, lba48);
s->req_nb_sectors = s->mult_sectors;
ide_sector_read(s);
lba48 = 1;
case WIN_MULTWRITE:
case CFA_WRITE_MULTI_WO_ERASE:
- if (!s->mult_sectors)
+ if (!s->bs) {
+ goto abort_cmd;
+ }
+ if (!s->mult_sectors) {
goto abort_cmd;
+ }
ide_cmd_lba48_transform(s, lba48);
s->error = 0;
s->status = SEEK_STAT | READY_STAT;
lba48 = 1;
case WIN_READDMA:
case WIN_READDMA_ONCE:
- if (!s->bs)
+ if (!s->bs) {
goto abort_cmd;
+ }
ide_cmd_lba48_transform(s, lba48);
ide_sector_start_dma(s, IDE_DMA_READ);
break;
lba48 = 1;
case WIN_WRITEDMA:
case WIN_WRITEDMA_ONCE:
- if (!s->bs)
+ if (!s->bs) {
goto abort_cmd;
+ }
ide_cmd_lba48_transform(s, lba48);
ide_sector_start_dma(s, IDE_DMA_WRITE);
s->media_changed = 1;
goto abort_cmd;
/* XXX: valid for CDROM ? */
switch(s->feature) {
- case 0xcc: /* reverting to power-on defaults enable */
- case 0x66: /* reverting to power-on defaults disable */
case 0x02: /* write cache enable */
+ bdrv_set_enable_write_cache(s->bs, true);
+ identify_data = (uint16_t *)s->identify_data;
+ put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1);
+ s->status = READY_STAT | SEEK_STAT;
+ ide_set_irq(s->bus);
+ break;
case 0x82: /* write cache disable */
+ bdrv_set_enable_write_cache(s->bs, false);
+ identify_data = (uint16_t *)s->identify_data;
+ put_le16(identify_data + 85, (1 << 14) | 1);
+ ide_flush_cache(s);
+ break;
+ case 0xcc: /* reverting to power-on defaults enable */
+ case 0x66: /* reverting to power-on defaults disable */
case 0xaa: /* read look-ahead enable */
case 0x55: /* read look-ahead disable */
case 0x05: /* set advanced power management mode */
break;
case 0x03: { /* set transfer mode */
uint8_t val = s->nsector & 0x07;
- uint16_t *identify_data = (uint16_t *)s->identify_data;
+ identify_data = (uint16_t *)s->identify_data;
switch (s->nsector >> 3) {
case 0x00: /* pio default */
break;
case CFA_ERASE_SECTORS:
case CFA_WEAR_LEVEL:
+#if 0
+ /* This one has the same ID as CFA_WEAR_LEVEL and is required for
+ Windows 8 to work with AHCI */
+ case WIN_SECURITY_FREEZE_LOCK:
+#endif
if (val == CFA_WEAR_LEVEL)
s->nsector = 0;
if (val == CFA_ERASE_SECTORS)
case SMART_READ_THRESH:
memset(s->io_buffer, 0, 0x200);
s->io_buffer[0] = 0x01; /* smart struct version */
- for (n=0; n<30; n++) {
- if (smart_attributes[n][0] == 0)
- break;
+ for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
s->io_buffer[2+1+(n*12)] = smart_attributes[n][11];
}
case SMART_READ_DATA:
memset(s->io_buffer, 0, 0x200);
s->io_buffer[0] = 0x01; /* smart struct version */
- for (n=0; n<30; n++) {
- if (smart_attributes[n][0] == 0) {
- break;
- }
+ for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
int i;
for(i = 0; i < 11; i++) {
s->io_buffer[2+i+(n*12)] = smart_attributes[n][i];
#ifdef DEBUG_IDE
printf("ide: reset\n");
#endif
+
+ if (s->pio_aiocb) {
+ bdrv_aio_cancel(s->pio_aiocb);
+ s->pio_aiocb = NULL;
+ }
+
if (s->drive_kind == IDE_CFATA)
s->mult_sectors = 0;
else
s->io_buffer_index = 0;
s->cd_sector_size = 0;
s->atapi_dma = 0;
+ s->tray_locked = 0;
+ s->tray_open = 0;
/* ATA DMA state */
s->io_buffer_size = 0;
s->req_nb_sectors = 0;
};
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
- const char *version, const char *serial)
+ const char *version, const char *serial, const char *model,
+ uint64_t wwn,
+ uint32_t cylinders, uint32_t heads, uint32_t secs,
+ int chs_trans)
{
- int cylinders, heads, secs;
uint64_t nb_sectors;
s->bs = bs;
s->drive_kind = kind;
bdrv_get_geometry(bs, &nb_sectors);
- bdrv_guess_geometry(bs, &cylinders, &heads, &secs);
- if (cylinders < 1 || cylinders > 16383) {
- error_report("cyls must be between 1 and 16383");
- return -1;
- }
- if (heads < 1 || heads > 16) {
- error_report("heads must be between 1 and 16");
- return -1;
- }
- if (secs < 1 || secs > 63) {
- error_report("secs must be between 1 and 63");
- return -1;
- }
s->cylinders = cylinders;
s->heads = heads;
s->sectors = secs;
+ s->chs_trans = chs_trans;
s->nb_sectors = nb_sectors;
+ s->wwn = wwn;
/* The SMART values should be preserved across power cycles
but they aren't. */
s->smart_enabled = 1;
}
}
if (serial) {
- strncpy(s->drive_serial_str, serial, sizeof(s->drive_serial_str));
+ pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), serial);
} else {
snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
"QM%05d", s->drive_serial);
}
+ if (model) {
+ pstrcpy(s->drive_model_str, sizeof(s->drive_model_str), model);
+ } else {
+ switch (kind) {
+ case IDE_CD:
+ strcpy(s->drive_model_str, "QEMU DVD-ROM");
+ break;
+ case IDE_CFATA:
+ strcpy(s->drive_model_str, "QEMU MICRODRIVE");
+ break;
+ default:
+ strcpy(s->drive_model_str, "QEMU HARDDISK");
+ break;
+ }
+ }
+
if (version) {
pstrcpy(s->version, sizeof(s->version), version);
} else {
- pstrcpy(s->version, sizeof(s->version), QEMU_VERSION);
+ pstrcpy(s->version, sizeof(s->version), qemu_get_version());
}
ide_reset(s);
void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
DriveInfo *hd1, qemu_irq irq)
{
- int i;
+ int i, trans;
DriveInfo *dinfo;
+ uint32_t cyls, heads, secs;
for(i = 0; i < 2; i++) {
dinfo = i == 0 ? hd0 : hd1;
ide_init1(bus, i);
if (dinfo) {
+ cyls = dinfo->cyls;
+ heads = dinfo->heads;
+ secs = dinfo->secs;
+ trans = dinfo->trans;
+ if (!cyls && !heads && !secs) {
+ hd_geometry_guess(dinfo->bdrv, &cyls, &heads, &secs, &trans);
+ } else if (trans == BIOS_ATA_TRANSLATION_AUTO) {
+ trans = hd_bios_chs_auto_trans(cyls, heads, secs);
+ }
+ if (cyls < 1 || cyls > 65535) {
+ error_report("cyls must be between 1 and 65535");
+ exit(1);
+ }
+ if (heads < 1 || heads > 16) {
+ error_report("heads must be between 1 and 16");
+ exit(1);
+ }
+ if (secs < 1 || secs > 255) {
+ error_report("secs must be between 1 and 255");
+ exit(1);
+ }
if (ide_init_drive(&bus->ifs[i], dinfo->bdrv,
- dinfo->media_cd ? IDE_CD : IDE_HD, NULL,
- *dinfo->serial ? dinfo->serial : NULL) < 0) {
+ dinfo->media_cd ? IDE_CD : IDE_HD,
+ NULL, dinfo->serial, NULL, 0,
+ cyls, heads, secs, trans) < 0) {
error_report("Can't set up IDE drive %s", dinfo->id);
exit(1);
}
{
IDEState *s = opaque;
- if (version_id < 3) {
- if (s->sense_key == UNIT_ATTENTION &&
- s->asc == ASC_MEDIUM_MAY_HAVE_CHANGED) {
- s->cdrom_changed = 1;
- }
+ if (s->identify_set) {
+ bdrv_set_enable_write_cache(s->bs, !!(s->identify_data[85] & (1 << 5)));
}
return 0;
}