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 = NOP supported, 0=SMART feature set enabled */
- put_le16(p + 85, (1 << 14) | 1);
+ /* 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 */
static void ide_rw_error(IDEState *s) {
ide_abort_command(s);
- ide_set_irq(s);
+ ide_set_irq(s->bus);
}
static void ide_sector_read(IDEState *s)
return;
}
ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
- ide_set_irq(s);
+ ide_set_irq(s->bus);
ide_set_sector(s, sector_num + n);
s->nsector -= n;
}
ide_transfer_stop(s);
s->error = ABRT_ERR;
s->status = READY_STAT | ERR_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
}
static int ide_handle_write_error(IDEState *s, int error, int op)
/* end of transfer ? */
if (s->nsector == 0) {
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
eot:
bm->status &= ~BM_STATUS_DMAING;
bm->status |= BM_STATUS_INT;
static void ide_sector_write_timer_cb(void *opaque)
{
IDEState *s = opaque;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
}
static void ide_sector_write(IDEState *s)
option _only_ to install Windows 2000. You must disable it
for normal use. */
qemu_mod_timer(s->sector_write_timer,
- qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
+ qemu_get_clock(vm_clock) + (get_ticks_per_sec() / 1000));
} else
#endif
{
- ide_set_irq(s);
+ ide_set_irq(s->bus);
}
}
/* end of transfer ? */
if (s->nsector == 0) {
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
eot:
bm->status &= ~BM_STATUS_DMAING;
bm->status |= BM_STATUS_INT;
s->error = 0;
s->status = READY_STAT | SEEK_STAT;
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
}
void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc)
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
s->sense_key = sense_key;
s->asc = asc;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
}
static void ide_atapi_cmd_check_status(IDEState *s)
s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4);
s->status = ERR_STAT;
s->nsector = 0;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
+}
+
+static void ide_flush_cb(void *opaque, int ret)
+{
+ IDEState *s = opaque;
+
+ /* XXX: how do we signal I/O errors here? */
+
+ s->status = READY_STAT | SEEK_STAT;
+ ide_set_irq(s->bus);
}
static inline void cpu_to_ube16(uint8_t *buf, int val)
ide_transfer_stop(s);
s->status = READY_STAT | SEEK_STAT;
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
#ifdef DEBUG_IDE_ATAPI
printf("status=0x%x\n", s->status);
#endif
s->packet_transfer_size -= size;
s->elementary_transfer_size -= size;
s->io_buffer_index += size;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
#ifdef DEBUG_IDE_ATAPI
printf("status=0x%x\n", s->status);
#endif
if (s->packet_transfer_size <= 0) {
s->status = READY_STAT | SEEK_STAT;
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
eot:
bm->status &= ~BM_STATUS_DMAING;
bm->status |= BM_STATUS_INT;
s->sense_key = SENSE_UNIT_ATTENTION;
s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
s->cdrom_changed = 1;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
}
static void ide_cmd_lba48_transform(IDEState *s, int lba48)
}
ide_abort_command(s);
}
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_SPECIFY:
case WIN_RECAL:
s->error = 0;
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_SETMULT:
if (s->is_cf && s->nsector == 0) {
s->mult_sectors = s->nsector & 0xff;
s->status = READY_STAT | SEEK_STAT;
}
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_VERIFY_EXT:
lba48 = 1;
/* do sector number check ? */
ide_cmd_lba48_transform(s, lba48);
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_READ_EXT:
lba48 = 1;
ide_cmd_lba48_transform(s, lba48);
ide_set_sector(s, s->nb_sectors - 1);
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_CHECKPOWERMODE1:
case WIN_CHECKPOWERMODE2:
s->nsector = 0xff; /* device active or idle */
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_SETFEATURES:
if (!s->bs)
case 0x42: /* enable Automatic Acoustic Mode */
case 0xc2: /* disable Automatic Acoustic Mode */
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case 0x03: { /* set transfer mode */
uint8_t val = s->nsector & 0x07;
goto abort_cmd;
}
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
}
default:
case WIN_FLUSH_CACHE:
case WIN_FLUSH_CACHE_EXT:
if (s->bs)
- bdrv_flush(s->bs);
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ bdrv_aio_flush(s->bs, ide_flush_cb, s);
+ else
+ ide_flush_cb(s, 0);
break;
case WIN_STANDBY:
case WIN_STANDBY2:
case WIN_SLEEPNOW1:
case WIN_SLEEPNOW2:
s->status = READY_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_SEEK:
if(s->is_cdrom)
goto abort_cmd;
/* XXX: Check that seek is within bounds */
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
/* ATAPI commands */
case WIN_PIDENTIFY:
} else {
ide_abort_command(s);
}
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_DIAGNOSE:
ide_set_signature(s);
s->error = 0x01; /* Device 0 passed, Device 1 passed or not
* present.
*/
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_SRST:
if (!s->is_cdrom)
goto abort_cmd;
s->error = 0x09; /* miscellaneous error */
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case CFA_ERASE_SECTORS:
case CFA_WEAR_LEVEL:
s->media_changed = 1;
s->error = 0x00;
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case CFA_TRANSLATE_SECTOR:
if (!s->is_cf)
s->io_buffer[0x19] = 0x00; /* Hot count */
s->io_buffer[0x1a] = 0x01; /* Hot count */
ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case CFA_ACCESS_METADATA_STORAGE:
if (!s->is_cf)
}
ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
s->status = 0x00; /* NOTE: READY is _not_ set */
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case IBM_SENSE_CONDITION:
if (!s->is_cf)
goto abort_cmd;
}
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case WIN_SMART:
case SMART_DISABLE:
s->smart_enabled = 0;
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case SMART_ENABLE:
s->smart_enabled = 1;
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case SMART_ATTR_AUTOSAVE:
switch (s->sector) {
goto abort_cmd;
}
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case SMART_STATUS:
if (!s->smart_errors) {
s->lcyl = 0xf4;
}
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case SMART_READ_THRESH:
memset(s->io_buffer, 0, 0x200);
s->io_buffer[511] = 0x100 - s->io_buffer[511];
s->status = READY_STAT | SEEK_STAT;
ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case SMART_READ_DATA:
memset(s->io_buffer, 0, 0x200);
s->io_buffer[511] = 0x100 - s->io_buffer[511];
s->status = READY_STAT | SEEK_STAT;
ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case SMART_READ_LOG:
switch (s->sector) {
}
s->status = READY_STAT | SEEK_STAT;
ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
case SMART_EXECUTE_OFFLINE:
switch (s->sector) {
s->smart_selftest_data[n+2] = 0x34; /* hour count lsb */
s->smart_selftest_data[n+3] = 0x12; /* hour count msb */
s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
default:
goto abort_cmd;
default:
abort_cmd:
ide_abort_command(s);
- ide_set_irq(s);
+ ide_set_irq(s->bus);
break;
}
}
ret = 0;
else
ret = s->status;
- qemu_irq_lower(s->irq);
+ qemu_irq_lower(bus->irq);
break;
}
#ifdef DEBUG_IDE
printf("ide: write control addr=0x%x val=%02x\n", addr, val);
#endif
/* common for both drives */
- if (!(bus->ifs[0].cmd & IDE_CMD_RESET) &&
+ if (!(bus->cmd & IDE_CMD_RESET) &&
(val & IDE_CMD_RESET)) {
/* reset low to high */
for(i = 0;i < 2; i++) {
s->status = BUSY_STAT | SEEK_STAT;
s->error = 0x01;
}
- } else if ((bus->ifs[0].cmd & IDE_CMD_RESET) &&
+ } else if ((bus->cmd & IDE_CMD_RESET) &&
!(val & IDE_CMD_RESET)) {
/* high to low */
for(i = 0;i < 2; i++) {
}
}
- bus->ifs[0].cmd = val;
- bus->ifs[1].cmd = val;
+ bus->cmd = val;
}
void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
s->media_changed = 0;
}
-void ide_init2(IDEBus *bus, BlockDriverState *hd0, BlockDriverState *hd1,
+void ide_init_drive(IDEState *s, DriveInfo *dinfo)
+{
+ int cylinders, heads, secs;
+ uint64_t nb_sectors;
+
+ if (dinfo && dinfo->bdrv) {
+ s->bs = dinfo->bdrv;
+ bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
+ s->cylinders = cylinders;
+ s->heads = heads;
+ s->sectors = secs;
+ s->nb_sectors = nb_sectors;
+ /* The SMART values should be preserved across power cycles
+ but they aren't. */
+ s->smart_enabled = 1;
+ s->smart_autosave = 1;
+ s->smart_errors = 0;
+ s->smart_selftest_count = 0;
+ if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
+ s->is_cdrom = 1;
+ bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
+ }
+ strncpy(s->drive_serial_str, drive_get_serial(s->bs),
+ sizeof(s->drive_serial_str));
+ }
+ if (strlen(s->drive_serial_str) == 0)
+ snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
+ "QM%05d", s->drive_serial);
+ ide_reset(s);
+}
+
+void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
qemu_irq irq)
{
IDEState *s;
static int drive_serial = 1;
- int i, cylinders, heads, secs;
- uint64_t nb_sectors;
+ int i;
for(i = 0; i < 2; i++) {
s = bus->ifs + i;
s->bus = bus;
s->unit = i;
- s->bs = (i == 0) ? hd0 : hd1;
- s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
- if (s->bs) {
- bdrv_get_geometry(s->bs, &nb_sectors);
- bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
- s->cylinders = cylinders;
- s->heads = heads;
- s->sectors = secs;
- s->nb_sectors = nb_sectors;
- /* The SMART values should be preserved across power cycles
- but they aren't. */
- s->smart_enabled = 1;
- s->smart_autosave = 1;
- s->smart_errors = 0;
- s->smart_selftest_count = 0;
- s->smart_selftest_data = qemu_blockalign(s->bs, 512);
- if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
- s->is_cdrom = 1;
- bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
- }
- }
s->drive_serial = drive_serial++;
- strncpy(s->drive_serial_str, drive_get_serial(s->bs),
- sizeof(s->drive_serial_str));
- if (strlen(s->drive_serial_str) == 0)
- snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
- "QM%05d", s->drive_serial);
- s->irq = irq;
+ s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
+ s->smart_selftest_data = qemu_blockalign(s->bs, 512);
s->sector_write_timer = qemu_new_timer(vm_clock,
ide_sector_write_timer_cb, s);
- ide_reset(s);
+ if (i == 0)
+ ide_init_drive(s, hd0);
+ if (i == 1)
+ ide_init_drive(s, hd1);
}
+ bus->irq = irq;
}
void ide_init_ioport(IDEBus *bus, int iobase, int iobase2)
/* XXX: if a transfer is pending, we do not save it yet */
}
+const VMStateDescription vmstate_ide_bus = {
+ .name = "ide_bus",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(cmd, IDEBus),
+ VMSTATE_UINT8(unit, IDEBus),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
void idebus_save(QEMUFile* f, IDEBus *bus)
{
- IDEState *s = idebus_active_if(bus);
- qemu_put_8s(f, &s->cmd);
- qemu_put_8s(f, &bus->unit);
+ vmstate_save_state(f, &vmstate_ide_bus, bus);
}
void idebus_load(QEMUFile* f, IDEBus *bus, int version_id)
{
- IDEState *s;
- uint8_t cmd;
-
- qemu_get_8s(f, &cmd);
- qemu_get_8s(f, &bus->unit);
- s = idebus_active_if(bus);
- s->cmd = cmd;
+ vmstate_load_state(f, &vmstate_ide_bus, bus, vmstate_ide_bus.version_id);
}
/***********************************************************/