aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--hw/ppc/spapr.c15
-rw-r--r--hw/ppc/spapr_drc.c52
-rw-r--r--hw/scsi/esp-pci.c1
-rw-r--r--hw/scsi/esp.c126
-rw-r--r--include/hw/ppc/spapr_drc.h5
-rw-r--r--include/hw/scsi/esp.h1
-rw-r--r--include/qemu/timer.h8
-rw-r--r--tests/qtest/am53c974-test.c218
-rw-r--r--tests/qtest/meson.build1
-rw-r--r--util/qemu-timer.c13
11 files changed, 303 insertions, 138 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 04beb34e7e..36055f14c5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1772,6 +1772,7 @@ F: include/hw/scsi/*
F: hw/scsi/*
F: tests/qtest/virtio-scsi-test.c
F: tests/qtest/fuzz-virtio-scsi-test.c
+F: tests/qtest/am53c974-test.c
T: git https://github.com/bonzini/qemu.git scsi-next
SSI
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 73a06df3b1..e4be00b732 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -3777,12 +3777,17 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
if (!spapr_drc_unplug_requested(drc)) {
spapr_drc_unplug_request(drc);
- spapr_hotplug_req_remove_by_index(drc);
- } else {
- error_setg(errp, "core-id %d unplug is still pending, %d seconds "
- "timeout remaining",
- cc->core_id, spapr_drc_unplug_timeout_remaining_sec(drc));
}
+
+ /*
+ * spapr_hotplug_req_remove_by_index is left unguarded, out of the
+ * "!spapr_drc_unplug_requested" check, to allow for multiple IRQ
+ * pulses removing the same CPU. Otherwise, in an failed hotunplug
+ * attempt (e.g. the kernel will refuse to remove the last online
+ * CPU), we will never attempt it again because unplug_requested
+ * will still be 'true' in that case.
+ */
+ spapr_hotplug_req_remove_by_index(drc);
}
int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 8a71b03800..9e16505fa1 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -57,8 +57,6 @@ static void spapr_drc_release(SpaprDrc *drc)
drck->release(drc->dev);
drc->unplug_requested = false;
- timer_del(drc->unplug_timeout_timer);
-
g_free(drc->fdt);
drc->fdt = NULL;
drc->fdt_start_offset = 0;
@@ -372,17 +370,6 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
} while (fdt_depth != 0);
}
-static void spapr_drc_start_unplug_timeout_timer(SpaprDrc *drc)
-{
- SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
-
- if (drck->unplug_timeout_seconds != 0) {
- timer_mod(drc->unplug_timeout_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
- drck->unplug_timeout_seconds * 1000);
- }
-}
-
void spapr_drc_attach(SpaprDrc *drc, DeviceState *d)
{
trace_spapr_drc_attach(spapr_drc_index(drc));
@@ -409,8 +396,6 @@ void spapr_drc_unplug_request(SpaprDrc *drc)
drc->unplug_requested = true;
- spapr_drc_start_unplug_timeout_timer(drc);
-
if (drc->state != drck->empty_state) {
trace_spapr_drc_awaiting_quiesce(spapr_drc_index(drc));
return;
@@ -419,15 +404,6 @@ void spapr_drc_unplug_request(SpaprDrc *drc)
spapr_drc_release(drc);
}
-int spapr_drc_unplug_timeout_remaining_sec(SpaprDrc *drc)
-{
- if (drc->unplug_requested) {
- return timer_deadline_ms(drc->unplug_timeout_timer) / 1000;
- }
-
- return 0;
-}
-
bool spapr_drc_reset(SpaprDrc *drc)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
@@ -499,23 +475,11 @@ static bool spapr_drc_needed(void *opaque)
spapr_drc_unplug_requested(drc);
}
-static int spapr_drc_post_load(void *opaque, int version_id)
-{
- SpaprDrc *drc = opaque;
-
- if (drc->unplug_requested) {
- spapr_drc_start_unplug_timeout_timer(drc);
- }
-
- return 0;
-}
-
static const VMStateDescription vmstate_spapr_drc = {
.name = "spapr_drc",
.version_id = 1,
.minimum_version_id = 1,
.needed = spapr_drc_needed,
- .post_load = spapr_drc_post_load,
.fields = (VMStateField []) {
VMSTATE_UINT32(state, SpaprDrc),
VMSTATE_END_OF_LIST()
@@ -526,15 +490,6 @@ static const VMStateDescription vmstate_spapr_drc = {
}
};
-static void drc_unplug_timeout_cb(void *opaque)
-{
- SpaprDrc *drc = opaque;
-
- if (drc->unplug_requested) {
- drc->unplug_requested = false;
- }
-}
-
static void drc_realize(DeviceState *d, Error **errp)
{
SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
@@ -557,11 +512,6 @@ static void drc_realize(DeviceState *d, Error **errp)
object_property_add_alias(root_container, link_name,
drc->owner, child_name);
g_free(link_name);
-
- drc->unplug_timeout_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- drc_unplug_timeout_cb,
- drc);
-
vmstate_register(VMSTATE_IF(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
drc);
trace_spapr_drc_realize_complete(spapr_drc_index(drc));
@@ -579,7 +529,6 @@ static void drc_unrealize(DeviceState *d)
name = g_strdup_printf("%x", spapr_drc_index(drc));
object_property_del(root_container, name);
g_free(name);
- timer_free(drc->unplug_timeout_timer);
}
SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
@@ -721,7 +670,6 @@ static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
drck->drc_name_prefix = "CPU ";
drck->release = spapr_core_release;
drck->dt_populate = spapr_core_dt_populate;
- drck->unplug_timeout_seconds = 15;
}
static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
index c3d3dab05e..9db10b1a48 100644
--- a/hw/scsi/esp-pci.c
+++ b/hw/scsi/esp-pci.c
@@ -332,6 +332,7 @@ static const VMStateDescription vmstate_esp_pci_scsi = {
.name = "pciespscsi",
.version_id = 2,
.minimum_version_id = 1,
+ .pre_save = esp_pre_save,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, PCIESPState),
VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 507ab363bc..b668acef82 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -95,45 +95,44 @@ void esp_request_cancelled(SCSIRequest *req)
scsi_req_unref(s->current_req);
s->current_req = NULL;
s->current_dev = NULL;
+ s->async_len = 0;
}
}
-static void esp_fifo_push(ESPState *s, uint8_t val)
+static void esp_fifo_push(Fifo8 *fifo, uint8_t val)
{
- if (fifo8_num_used(&s->fifo) == ESP_FIFO_SZ) {
+ if (fifo8_num_used(fifo) == fifo->capacity) {
trace_esp_error_fifo_overrun();
return;
}
- fifo8_push(&s->fifo, val);
+ fifo8_push(fifo, val);
}
-static uint8_t esp_fifo_pop(ESPState *s)
+static uint8_t esp_fifo_pop(Fifo8 *fifo)
{
- if (fifo8_is_empty(&s->fifo)) {
+ if (fifo8_is_empty(fifo)) {
return 0;
}
- return fifo8_pop(&s->fifo);
+ return fifo8_pop(fifo);
}
-static void esp_cmdfifo_push(ESPState *s, uint8_t val)
+static uint32_t esp_fifo_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen)
{
- if (fifo8_num_used(&s->cmdfifo) == ESP_CMDFIFO_SZ) {
- trace_esp_error_fifo_overrun();
- return;
- }
-
- fifo8_push(&s->cmdfifo, val);
-}
+ const uint8_t *buf;
+ uint32_t n;
-static uint8_t esp_cmdfifo_pop(ESPState *s)
-{
- if (fifo8_is_empty(&s->cmdfifo)) {
+ if (maxlen == 0) {
return 0;
}
- return fifo8_pop(&s->cmdfifo);
+ buf = fifo8_pop_buf(fifo, maxlen, &n);
+ if (dest) {
+ memcpy(dest, buf, n);
+ }
+
+ return n;
}
static uint32_t esp_get_tc(ESPState *s)
@@ -170,9 +169,9 @@ static uint8_t esp_pdma_read(ESPState *s)
uint8_t val;
if (s->do_cmd) {
- val = esp_cmdfifo_pop(s);
+ val = esp_fifo_pop(&s->cmdfifo);
} else {
- val = esp_fifo_pop(s);
+ val = esp_fifo_pop(&s->fifo);
}
return val;
@@ -187,9 +186,9 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
}
if (s->do_cmd) {
- esp_cmdfifo_push(s, val);
+ esp_fifo_push(&s->cmdfifo, val);
} else {
- esp_fifo_push(s, val);
+ esp_fifo_push(&s->fifo, val);
}
dmalen--;
@@ -208,7 +207,6 @@ static int esp_select(ESPState *s)
if (s->current_req) {
/* Started a new command before the old one finished. Cancel it. */
scsi_req_cancel(s->current_req);
- s->async_len = 0;
}
s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
@@ -245,6 +243,7 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
}
if (s->dma_memory_read) {
s->dma_memory_read(s->dma_opaque, buf, dmalen);
+ dmalen = MIN(fifo8_num_free(&s->cmdfifo), dmalen);
fifo8_push_all(&s->cmdfifo, buf, dmalen);
} else {
if (esp_select(s) < 0) {
@@ -260,11 +259,12 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
if (dmalen == 0) {
return 0;
}
- memcpy(buf, fifo8_pop_buf(&s->fifo, dmalen, &n), dmalen);
- if (dmalen >= 3) {
+ n = esp_fifo_pop_buf(&s->fifo, buf, dmalen);
+ if (n >= 3) {
buf[0] = buf[2] >> 5;
}
- fifo8_push_all(&s->cmdfifo, buf, dmalen);
+ n = MIN(fifo8_num_free(&s->cmdfifo), n);
+ fifo8_push_all(&s->cmdfifo, buf, n);
}
trace_esp_get_cmd(dmalen, target);
@@ -277,16 +277,19 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
static void do_busid_cmd(ESPState *s, uint8_t busid)
{
- uint32_t n, cmdlen;
+ uint32_t cmdlen;
int32_t datalen;
int lun;
SCSIDevice *current_lun;
- uint8_t *buf;
+ uint8_t buf[ESP_CMDFIFO_SZ];
trace_esp_do_busid_cmd(busid);
lun = busid & 7;
cmdlen = fifo8_num_used(&s->cmdfifo);
- buf = (uint8_t *)fifo8_pop_buf(&s->cmdfifo, cmdlen, &n);
+ if (!cmdlen || !s->current_dev) {
+ return;
+ }
+ esp_fifo_pop_buf(&s->cmdfifo, buf, cmdlen);
current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
s->current_req = scsi_req_new(current_lun, 0, lun, buf, s);
@@ -318,14 +321,15 @@ static void do_busid_cmd(ESPState *s, uint8_t busid)
static void do_cmd(ESPState *s)
{
- uint8_t busid = fifo8_pop(&s->cmdfifo);
- uint32_t n;
+ uint8_t busid = esp_fifo_pop(&s->cmdfifo);
+ int len;
s->cmdfifo_cdb_offset--;
/* Ignore extended messages for now */
if (s->cmdfifo_cdb_offset) {
- fifo8_pop_buf(&s->cmdfifo, s->cmdfifo_cdb_offset, &n);
+ len = MIN(s->cmdfifo_cdb_offset, fifo8_num_used(&s->cmdfifo));
+ esp_fifo_pop_buf(&s->cmdfifo, NULL, len);
s->cmdfifo_cdb_offset = 0;
}
@@ -353,6 +357,7 @@ static void handle_satn(ESPState *s)
cmdlen = get_cmd(s, ESP_CMDFIFO_SZ);
if (cmdlen > 0) {
s->cmdfifo_cdb_offset = 1;
+ s->do_cmd = 0;
do_cmd(s);
} else if (cmdlen == 0) {
s->do_cmd = 1;
@@ -386,6 +391,7 @@ static void handle_s_without_atn(ESPState *s)
cmdlen = get_cmd(s, ESP_CMDFIFO_SZ);
if (cmdlen > 0) {
s->cmdfifo_cdb_offset = 0;
+ s->do_cmd = 0;
do_busid_cmd(s, 0);
} else if (cmdlen == 0) {
s->do_cmd = 1;
@@ -445,18 +451,16 @@ static void write_response_pdma_cb(ESPState *s)
static void write_response(ESPState *s)
{
- uint32_t n;
+ uint8_t buf[2];
trace_esp_write_response(s->status);
- fifo8_reset(&s->fifo);
- esp_fifo_push(s, s->status);
- esp_fifo_push(s, 0);
+ buf[0] = s->status;
+ buf[1] = 0;
if (s->dma) {
if (s->dma_memory_write) {
- s->dma_memory_write(s->dma_opaque,
- (uint8_t *)fifo8_pop_buf(&s->fifo, 2, &n), 2);
+ s->dma_memory_write(s->dma_opaque, buf, 2);
s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
s->rregs[ESP_RSEQ] = SEQ_CD;
@@ -466,7 +470,8 @@ static void write_response(ESPState *s)
return;
}
} else {
- s->ti_size = 2;
+ fifo8_reset(&s->fifo);
+ fifo8_push_all(&s->fifo, buf, 2);
s->rregs[ESP_RFLAGS] = 2;
}
esp_raise_irq(s);
@@ -496,11 +501,15 @@ static void do_dma_pdma_cb(ESPState *s)
return;
}
+ if (!s->current_req) {
+ return;
+ }
+
if (to_device) {
/* Copy FIFO data to device */
len = MIN(s->async_len, ESP_FIFO_SZ);
len = MIN(len, fifo8_num_used(&s->fifo));
- memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
+ n = esp_fifo_pop_buf(&s->fifo, s->async_buf, len);
s->async_buf += n;
s->async_len -= n;
s->ti_size += n;
@@ -508,7 +517,7 @@ static void do_dma_pdma_cb(ESPState *s)
if (n < len) {
/* Unaligned accesses can cause FIFO wraparound */
len = len - n;
- memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
+ n = esp_fifo_pop_buf(&s->fifo, s->async_buf, len);
s->async_buf += n;
s->async_len -= n;
s->ti_size += n;
@@ -527,11 +536,9 @@ static void do_dma_pdma_cb(ESPState *s)
return;
} else {
if (s->async_len == 0) {
- if (s->current_req) {
- /* Defer until the scsi layer has completed */
- scsi_req_continue(s->current_req);
- s->data_in_ready = false;
- }
+ /* Defer until the scsi layer has completed */
+ scsi_req_continue(s->current_req);
+ s->data_in_ready = false;
return;
}
@@ -573,6 +580,7 @@ static void esp_do_dma(ESPState *s)
cmdlen = fifo8_num_used(&s->cmdfifo);
trace_esp_do_dma(cmdlen, len);
if (s->dma_memory_read) {
+ len = MIN(len, fifo8_num_free(&s->cmdfifo));
s->dma_memory_read(s->dma_opaque, buf, len);
fifo8_push_all(&s->cmdfifo, buf, len);
} else {
@@ -604,6 +612,9 @@ static void esp_do_dma(ESPState *s)
}
return;
}
+ if (!s->current_req) {
+ return;
+ }
if (s->async_len == 0) {
/* Defer until data is available. */
return;
@@ -641,7 +652,7 @@ static void esp_do_dma(ESPState *s)
*/
if (len < esp_get_tc(s) && esp_get_tc(s) <= ESP_FIFO_SZ) {
while (fifo8_num_used(&s->fifo) < ESP_FIFO_SZ) {
- esp_fifo_push(s, 0);
+ esp_fifo_push(&s->fifo, 0);
len++;
}
}
@@ -683,7 +694,7 @@ static void esp_do_dma(ESPState *s)
static void esp_do_nodma(ESPState *s)
{
int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
- uint32_t cmdlen, n;
+ uint32_t cmdlen;
int len;
if (s->do_cmd) {
@@ -713,6 +724,10 @@ static void esp_do_nodma(ESPState *s)
return;
}
+ if (!s->current_req) {
+ return;
+ }
+
if (s->async_len == 0) {
/* Defer until data is available. */
return;
@@ -720,7 +735,7 @@ static void esp_do_nodma(ESPState *s)
if (to_device) {
len = MIN(fifo8_num_used(&s->fifo), ESP_FIFO_SZ);
- memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
+ esp_fifo_pop_buf(&s->fifo, s->async_buf, len);
s->async_buf += len;
s->async_len -= len;
s->ti_size += len;
@@ -890,7 +905,7 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
s->rregs[ESP_FIFO] = 0;
} else {
- s->rregs[ESP_FIFO] = esp_fifo_pop(s);
+ s->rregs[ESP_FIFO] = esp_fifo_pop(&s->fifo);
}
val = s->rregs[ESP_FIFO];
break;
@@ -939,9 +954,9 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
break;
case ESP_FIFO:
if (s->do_cmd) {
- esp_cmdfifo_push(s, val);
+ esp_fifo_push(&s->cmdfifo, val);
} else {
- esp_fifo_push(s, val);
+ esp_fifo_push(&s->fifo, val);
}
/* Non-DMA transfers raise an interrupt after every byte */
@@ -1076,9 +1091,10 @@ static bool esp_is_version_5(void *opaque, int version_id)
return version_id == 5;
}
-static int esp_pre_save(void *opaque)
+int esp_pre_save(void *opaque)
{
- ESPState *s = ESP(opaque);
+ ESPState *s = ESP(object_resolve_path_component(
+ OBJECT(opaque), "esp"));
s->mig_version_id = vmstate_esp.version_id;
return 0;
@@ -1114,7 +1130,6 @@ const VMStateDescription vmstate_esp = {
.name = "esp",
.version_id = 5,
.minimum_version_id = 3,
- .pre_save = esp_pre_save,
.post_load = esp_post_load,
.fields = (VMStateField[]) {
VMSTATE_BUFFER(rregs, ESPState),
@@ -1304,6 +1319,7 @@ static const VMStateDescription vmstate_sysbus_esp_scsi = {
.name = "sysbusespscsi",
.version_id = 2,
.minimum_version_id = 1,
+ .pre_save = esp_pre_save,
.fields = (VMStateField[]) {
VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2),
VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
index 26599c385a..02a63b3666 100644
--- a/include/hw/ppc/spapr_drc.h
+++ b/include/hw/ppc/spapr_drc.h
@@ -187,8 +187,6 @@ typedef struct SpaprDrc {
bool unplug_requested;
void *fdt;
int fdt_start_offset;
-
- QEMUTimer *unplug_timeout_timer;
} SpaprDrc;
struct SpaprMachineState;
@@ -211,8 +209,6 @@ typedef struct SpaprDrcClass {
int (*dt_populate)(SpaprDrc *drc, struct SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp);
-
- int unplug_timeout_seconds;
} SpaprDrcClass;
typedef struct SpaprDrcPhysical {
@@ -248,7 +244,6 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask);
*/
void spapr_drc_attach(SpaprDrc *drc, DeviceState *d);
void spapr_drc_unplug_request(SpaprDrc *drc);
-int spapr_drc_unplug_timeout_remaining_sec(SpaprDrc *drc);
/*
* Reset all DRCs, causing pending hot-plug/unplug requests to complete.
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 95088490aa..aada3680b7 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -157,5 +157,6 @@ void esp_hard_reset(ESPState *s);
uint64_t esp_reg_read(ESPState *s, uint32_t saddr);
void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val);
extern const VMStateDescription vmstate_esp;
+int esp_pre_save(void *opaque);
#endif
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 301fa47b42..88ef114689 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -797,14 +797,6 @@ static inline int64_t get_max_clock_jump(void)
return 60 * NANOSECONDS_PER_SECOND;
}
-/**
- * timer_deadline_ms:
- *
- * Returns the remaining miliseconds for @timer to expire, or zero
- * if the timer is no longer pending.
- */
-int64_t timer_deadline_ms(QEMUTimer *timer);
-
/*
* Low level clock functions
*/
diff --git a/tests/qtest/am53c974-test.c b/tests/qtest/am53c974-test.c
new file mode 100644
index 0000000000..d996866cd4
--- /dev/null
+++ b/tests/qtest/am53c974-test.c
@@ -0,0 +1,218 @@
+/*
+ * QTest testcase for am53c974
+ *
+ * Copyright (c) 2021 Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqos/libqtest.h"
+
+
+static void test_cmdfifo_underflow_ok(void)
+{
+ QTestState *s = qtest_init(
+ "-device am53c974,id=scsi "
+ "-device scsi-hd,drive=disk0 -drive "
+ "id=disk0,if=none,file=null-co://,format=raw -nodefaults");
+ qtest_outl(s, 0xcf8, 0x80001004);
+ qtest_outw(s, 0xcfc, 0x01);
+ qtest_outl(s, 0xcf8, 0x8000100e);
+ qtest_outl(s, 0xcfc, 0x8a000000);
+ qtest_outl(s, 0x8a09, 0x42000000);
+ qtest_outl(s, 0x8a0d, 0x00);
+ qtest_outl(s, 0x8a0b, 0x1000);
+ qtest_quit(s);
+}
+
+/* Reported as crash_1548bd10e7 */
+static void test_cmdfifo_underflow2_ok(void)
+{
+ QTestState *s = qtest_init(
+ "-device am53c974,id=scsi -device scsi-hd,drive=disk0 "
+ "-drive id=disk0,if=none,file=null-co://,format=raw -nodefaults");
+ qtest_outl(s, 0xcf8, 0x80001010);
+ qtest_outl(s, 0xcfc, 0xc000);
+ qtest_outl(s, 0xcf8, 0x80001004);
+ qtest_outw(s, 0xcfc, 0x01);
+ qtest_outw(s, 0xc00c, 0x41);
+ qtest_outw(s, 0xc00a, 0x00);
+ qtest_outl(s, 0xc00a, 0x00);
+ qtest_outw(s, 0xc00c, 0x43);
+ qtest_outw(s, 0xc00b, 0x00);
+ qtest_outw(s, 0xc00b, 0x00);
+ qtest_outw(s, 0xc00c, 0x00);
+ qtest_outl(s, 0xc00a, 0x00);
+ qtest_outw(s, 0xc00a, 0x00);
+ qtest_outl(s, 0xc00a, 0x00);
+ qtest_outw(s, 0xc00c, 0x00);
+ qtest_outl(s, 0xc00a, 0x00);
+ qtest_outw(s, 0xc00a, 0x00);
+ qtest_outl(s, 0xc00a, 0x00);
+ qtest_outw(s, 0xc00c, 0x00);
+ qtest_outl(s, 0xc00a, 0x00);
+ qtest_outw(s, 0xc00a, 0x00);
+ qtest_outl(s, 0xc00a, 0x00);
+ qtest_outw(s, 0xc00c, 0x00);
+ qtest_outl(s, 0xc00a, 0x00);
+ qtest_outl(s, 0xc006, 0x00);
+ qtest_outl(s, 0xc00b, 0x00);
+ qtest_outw(s, 0xc00b, 0x0800);
+ qtest_outw(s, 0xc00b, 0x00);
+ qtest_outw(s, 0xc00b, 0x00);
+ qtest_outl(s, 0xc006, 0x00);
+ qtest_outl(s, 0xc00b, 0x00);
+ qtest_outw(s, 0xc00b, 0x0800);
+ qtest_outw(s, 0xc00b, 0x00);
+ qtest_outw(s, 0xc00b, 0x4100);
+ qtest_outw(s, 0xc00a, 0x00);
+ qtest_outl(s, 0xc00a, 0x100000);
+ qtest_outl(s, 0xc00a, 0x00);
+ qtest_outw(s, 0xc00c, 0x43);
+ qtest_outl(s, 0xc00a, 0x100000);
+ qtest_outl(s, 0xc00a, 0x100000);
+ qtest_quit(s);
+}
+
+static void test_cmdfifo_overflow_ok(void)
+{
+ QTestState *s = qtest_init(
+ "-device am53c974,id=scsi "
+ "-device scsi-hd,drive=disk0 -drive "
+ "id=disk0,if=none,file=null-co://,format=raw -nodefaults");
+ qtest_outl(s, 0xcf8, 0x80001004);
+ qtest_outw(s, 0xcfc, 0x01);
+ qtest_outl(s, 0xcf8, 0x8000100e);
+ qtest_outl(s, 0xcfc, 0x0e000000);
+ qtest_outl(s, 0xe40, 0x03);
+ qtest_outl(s, 0xe0b, 0x4100);
+ qtest_outl(s, 0xe0b, 0x9000);
+ qtest_quit(s);
+}
+
+/* Reported as crash_530ff2e211 */
+static void test_cmdfifo_overflow2_ok(void)
+{
+ QTestState *s = qtest_init(
+ "-device am53c974,id=scsi -device scsi-hd,drive=disk0 "
+ "-drive id=disk0,if=none,file=null-co://,format=raw -nodefaults");
+ qtest_outl(s, 0xcf8, 0x80001010);
+ qtest_outl(s, 0xcfc, 0xc000);
+ qtest_outl(s, 0xcf8, 0x80001004);
+ qtest_outw(s, 0xcfc, 0x01);
+ qtest_outl(s, 0xc00b, 0x4100);
+ qtest_outw(s, 0xc00b, 0xc200);
+ qtest_outl(s, 0xc03f, 0x0300);
+ qtest_quit(s);
+}
+
+/* Reported as crash_0900379669 */
+static void test_fifo_pop_buf(void)
+{
+ QTestState *s = qtest_init(
+ "-device am53c974,id=scsi -device scsi-hd,drive=disk0 "
+ "-drive id=disk0,if=none,file=null-co://,format=raw -nodefaults");
+ qtest_outl(s, 0xcf8, 0x80001010);
+ qtest_outl(s, 0xcfc, 0xc000);
+ qtest_outl(s, 0xcf8, 0x80001004);
+ qtest_outw(s, 0xcfc, 0x01);
+ qtest_outb(s, 0xc000, 0x4);
+ qtest_outb(s, 0xc008, 0xa0);
+ qtest_outl(s, 0xc03f, 0x0300);
+ qtest_outl(s, 0xc00b, 0xc300);
+ qtest_outw(s, 0xc00b, 0x9000);
+ qtest_outl(s, 0xc00b, 0xc300);
+ qtest_outl(s, 0xc00b, 0xc300);
+ qtest_outl(s, 0xc00b, 0xc300);
+ qtest_outw(s, 0xc00b, 0x9000);
+ qtest_outw(s, 0xc00b, 0x1000);
+ qtest_quit(s);
+}
+
+static void test_target_selected_ok(void)
+{
+ QTestState *s = qtest_init(
+ "-device am53c974,id=scsi "
+ "-device scsi-hd,drive=disk0 -drive "
+ "id=disk0,if=none,file=null-co://,format=raw -nodefaults");
+ qtest_outl(s, 0xcf8, 0x80001001);
+ qtest_outl(s, 0xcfc, 0x01000000);
+ qtest_outl(s, 0xcf8, 0x8000100e);
+ qtest_outl(s, 0xcfc, 0xef800000);
+ qtest_outl(s, 0xef8b, 0x4100);
+ qtest_outw(s, 0xef80, 0x01);
+ qtest_outl(s, 0xefc0, 0x03);
+ qtest_outl(s, 0xef8b, 0xc100);
+ qtest_outl(s, 0xef8b, 0x9000);
+ qtest_quit(s);
+}
+
+static void test_fifo_underflow_on_write_ok(void)
+{
+ QTestState *s = qtest_init(
+ "-device am53c974,id=scsi "
+ "-device scsi-hd,drive=disk0 -drive "
+ "id=disk0,if=none,file=null-co://,format=raw -nodefaults");
+ qtest_outl(s, 0xcf8, 0x80001010);
+ qtest_outl(s, 0xcfc, 0xc000);
+ qtest_outl(s, 0xcf8, 0x80001004);
+ qtest_outw(s, 0xcfc, 0x01);
+ qtest_outl(s, 0xc008, 0x0a);
+ qtest_outl(s, 0xc009, 0x41000000);
+ qtest_outl(s, 0xc009, 0x41000000);
+ qtest_outl(s, 0xc00b, 0x1000);
+ qtest_quit(s);
+}
+
+static void test_cancelled_request_ok(void)
+{
+ QTestState *s = qtest_init(
+ "-device am53c974,id=scsi "
+ "-device scsi-hd,drive=disk0 -drive "
+ "id=disk0,if=none,file=null-co://,format=raw -nodefaults");
+ qtest_outl(s, 0xcf8, 0x80001010);
+ qtest_outl(s, 0xcfc, 0xc000);
+ qtest_outl(s, 0xcf8, 0x80001004);
+ qtest_outw(s, 0xcfc, 0x05);
+ qtest_outb(s, 0xc046, 0x02);
+ qtest_outl(s, 0xc00b, 0xc100);
+ qtest_outl(s, 0xc040, 0x03);
+ qtest_outl(s, 0xc040, 0x03);
+ qtest_bufwrite(s, 0x0, "\x41", 0x1);
+ qtest_outl(s, 0xc00b, 0xc100);
+ qtest_outw(s, 0xc040, 0x02);
+ qtest_outw(s, 0xc040, 0x81);
+ qtest_outl(s, 0xc00b, 0x9000);
+ qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+ const char *arch = qtest_get_arch();
+
+ g_test_init(&argc, &argv, NULL);
+
+ if (strcmp(arch, "i386") == 0) {
+ qtest_add_func("am53c974/test_cmdfifo_underflow_ok",
+ test_cmdfifo_underflow_ok);
+ qtest_add_func("am53c974/test_cmdfifo_underflow2_ok",
+ test_cmdfifo_underflow2_ok);
+ qtest_add_func("am53c974/test_cmdfifo_overflow_ok",
+ test_cmdfifo_overflow_ok);
+ qtest_add_func("am53c974/test_cmdfifo_overflow2_ok",
+ test_cmdfifo_overflow2_ok);
+ qtest_add_func("am53c974/test_fifo_pop_buf",
+ test_fifo_pop_buf);
+ qtest_add_func("am53c974/test_target_selected_ok",
+ test_target_selected_ok);
+ qtest_add_func("am53c974/test_fifo_underflow_on_write_ok",
+ test_fifo_underflow_on_write_ok);
+ qtest_add_func("am53c974/test_cancelled_request_ok",
+ test_cancelled_request_ok);
+ }
+
+ return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 420cd9986e..0c76738921 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -65,6 +65,7 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-swtpm-test'] : []) + \
(config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) + \
(config_all_devices.has_key('CONFIG_E1000E_PCI_EXPRESS') ? ['fuzz-e1000e-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
qtests_pci + \
['fdc-test',
'ide-test',
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
index be529c1f65..f36c75e594 100644
--- a/util/qemu-timer.c
+++ b/util/qemu-timer.c
@@ -242,19 +242,6 @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
return delta;
}
-/*
- * Returns the time remaining for the deadline, in ms.
- */
-int64_t timer_deadline_ms(QEMUTimer *timer)
-{
- if (timer_pending(timer)) {
- return qemu_timeout_ns_to_ms(timer->expire_time) -
- qemu_clock_get_ms(timer->timer_list->clock->type);
- }
-
- return 0;
-}
-
/* Calculate the soonest deadline across all timerlists attached
* to the clock. This is used for the icount timeout so we
* ignore whether or not the clock should be used in deadline